Skip to content

Commit

Permalink
Code Connect v1.0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
figma-bot committed Aug 13, 2024
1 parent c890f16 commit f3e11fe
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 36 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Code Connect v1.0.5 (13th August 2024)

## Fixed

### React
- Fixed an issue around creation of Code Connect files from the CLI assistant (fixes https://github.com/figma/code-connect/issues/125)

# Code Connect v1.0.4 (7th August 2024)

## Fixed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// no exports
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ interface ButtonProps {
* @param disabled disable the button
* @returns JSX element
*/
export const PrimaryButton = ({ children, disabled = false }: ButtonProps) => {
const InnerComponent = ({ children, disabled = false }: ButtonProps) => {
return <button disabled={disabled}>{children}</button>
}

// Aliases not yet supported by wizard, signature gen should fail gracefully
export const PrimaryButton = InnerComponent
2 changes: 1 addition & 1 deletion cli/src/connect/wizard/__test__/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('getFilepathExportsFromFiles', () => {
})

it('generates list of file component keys from ProjectInfo', () => {
const result = getFilepathExportsFromFiles(projectInfo)
const result = getFilepathExportsFromFiles(projectInfo, {} as any)
expect(result.map((filepath) => path.parse(filepath).base)).toEqual([
'MyComponent.tsx~MyComponent',
'MyComponent.tsx~MyComponentProps', // TODO ideally we'd filter out by type here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ describe('Prop mapping', () => {
},
},
},
cmd: {} as any,
})
expect(result).toEqual({
'Has Icon': {
Expand Down
20 changes: 14 additions & 6 deletions cli/src/connect/wizard/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { logger, success } from '../../common/logging'
import path from 'path'
import prompts, { Choice } from 'prompts'
import { isFigmaConnectFile } from '../../react/parser'
import { BaseCommand } from '../../commands/connect'


/**
Expand Down Expand Up @@ -118,7 +119,7 @@ export function getComponentOptionsMap(filepathExports: string[]) {
* @param projectInfo
* @returns an array of components in the format `${filepath}~${componentName}
*/
export function getFilepathExportsFromFiles(projectInfo: ProjectInfo) {
export function getFilepathExportsFromFiles(projectInfo: ProjectInfo, cmd: BaseCommand) {
return projectInfo.files.reduce((options, filepath) => {
if (projectInfo.config.parser === 'react') {
const { tsProgram } = projectInfo as ReactProjectInfo
Expand All @@ -128,12 +129,19 @@ export function getFilepathExportsFromFiles(projectInfo: ProjectInfo) {
if (!sourceFile) {
throw new Error(`Could not parse file ${filepath}`)
}
const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile)!
const exports = checker.getExportsOfModule(sourceFileSymbol)
try {
const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile)!
const exports = checker.getExportsOfModule(sourceFileSymbol)

exports.forEach((exp) => {
options.push(getFilepathExport(filepath, exp.getName()))
})
exports.forEach((exp) => {
options.push(getFilepathExport(filepath, exp.getName()))
})
} catch (e) {
if (cmd.verbose) {
logger.warn(`Could not get exports from ${filepath}`)
}
// ignore invalid files
}
}
} else {
options.push(filepath)
Expand Down
70 changes: 43 additions & 27 deletions cli/src/connect/wizard/prop_mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { ComponentTypeSignature, extractComponentTypeSignature } from '../../rea
import { FigmaRestApi } from '../figma_rest_api'
import { PropMapping, SupportedMappingType } from '../parser_executable_types'
import { MatchData, Searcher } from 'fast-fuzzy'
import { BaseCommand } from '../../commands/connect'
import { logger } from '../../common/logging'

const PROP_MINIMUM_MATCH_THRESHOLD = 0.8

Expand Down Expand Up @@ -97,17 +99,28 @@ export function generatePropMapping({
filepath,
projectInfo,
component,
cmd,
}: {
exportName: string
filepath: string
projectInfo: ReactProjectInfo
component: FigmaRestApi.Component
}): PropMapping {
const signature = extractSignature({
nameToFind: exportName,
sourceFilePath: filepath,
projectInfo,
})
cmd: BaseCommand
}): PropMapping | undefined {
let signature: ComponentTypeSignature

try {
signature = extractSignature({
nameToFind: exportName,
sourceFilePath: filepath,
projectInfo,
})
} catch (e) {
if (cmd.verbose) {
logger.warn(`Could not extract signature for "${exportName}" in ${filepath}`)
}
return undefined
}

const matchableCodeProps = Object.keys(signature).reduce((acc, key) => {
acc[getMatchableStr(key)] = key
Expand All @@ -123,28 +136,31 @@ export function generatePropMapping({
const searchSpace = Object.keys(matchableCodeProps)
const searcher = new Searcher(searchSpace)

Object.entries(component.componentPropertyDefinitions).forEach(
([propertyName, componentPropertyDefinition]) => {
const results = searcher.search(getMatchableStr(propertyName), { returnMatchData: true })
const bestMatch = results[0]
const matchingCodeProp = matchableCodeProps[bestMatch?.item]

if (
bestMatch &&
bestMatch.score > PROP_MINIMUM_MATCH_THRESHOLD &&
getComponentPropertyTypeFromSignature(signature[matchingCodeProp]) ===
componentPropertyDefinition.type &&
isBestMatchForProp(bestMatch)
) {
matchedPropScores[bestMatch.item] = {
codePropName: matchingCodeProp,
figmaPropName: propertyName,
figmaPropType: componentPropertyDefinition.type,
score: bestMatch.score,
if (component.componentPropertyDefinitions) {
Object.entries(component.componentPropertyDefinitions).forEach(
([propertyName, componentPropertyDefinition]) => {
const results = searcher.search(getMatchableStr(propertyName), { returnMatchData: true })
const bestMatch = results[0]
const matchingCodeProp = matchableCodeProps[bestMatch?.item]

if (
bestMatch &&
bestMatch.score > PROP_MINIMUM_MATCH_THRESHOLD &&
getComponentPropertyTypeFromSignature(signature[matchingCodeProp]) ===
componentPropertyDefinition.type &&
isBestMatchForProp(bestMatch)
) {
matchedPropScores[bestMatch.item] = {
codePropName: matchingCodeProp,
figmaPropName: propertyName,
figmaPropType: componentPropertyDefinition.type,
score: bestMatch.score,
}
}
}
},
)
},
)
}

return Object.entries(matchedPropScores).reduce(
(acc, [_, { codePropName, figmaPropName, figmaPropType }]) => {
acc[figmaPropName] = {
Expand Down
9 changes: 8 additions & 1 deletion cli/src/connect/wizard/run_wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,14 @@ async function createCodeConnectFiles({
unconnectedComponentsMap,
outDir: outDirArg,
projectInfo,
cmd,
}: {
figmaFileUrl: string
linkedNodeIdsToFilepathExports: Record<string, string>
unconnectedComponentsMap: Record<string, FigmaRestApi.Component>
outDir: string | null
projectInfo: ProjectInfo
cmd: BaseCommand
}) {
for (const [nodeId, filepathExport] of Object.entries(linkedNodeIdsToFilepathExports)) {
const urlObj = new URL(figmaFileUrl)
Expand All @@ -465,6 +467,7 @@ async function createCodeConnectFiles({
exportName,
projectInfo: projectInfo as ReactProjectInfo,
component: unconnectedComponentsMap[nodeId],
cmd,
})
: undefined,
component: {
Expand Down Expand Up @@ -585,10 +588,12 @@ async function askForTopLevelDirectoryOrDetermineFromConfig({
dir,
hasConfigFile,
config,
cmd,
}: {
dir: string
hasConfigFile: boolean
config: CodeConnectConfig
cmd: BaseCommand
}) {
let componentDirectory: string | null = null

Expand Down Expand Up @@ -639,7 +644,7 @@ async function askForTopLevelDirectoryOrDetermineFromConfig({
projectInfo = getReactProjectInfo(projectInfo as ReactProjectInfo)
}

const filepathExports = getFilepathExportsFromFiles(projectInfo)
const filepathExports = getFilepathExportsFromFiles(projectInfo, cmd)
spinner.stop()

if (!filepathExports.length) {
Expand Down Expand Up @@ -709,6 +714,7 @@ export async function runWizard(cmd: BaseCommand) {
dir,
hasConfigFile,
config,
cmd,
})

const { figmaFileUrl } = await askQuestionOrExit({
Expand Down Expand Up @@ -815,5 +821,6 @@ export async function runWizard(cmd: BaseCommand) {
figmaFileUrl,
outDir,
projectInfo,
cmd,
})
}

0 comments on commit f3e11fe

Please sign in to comment.