{"version":3,"file":"autolinking.js","sourceRoot":"","sources":["../../../src/connect/wizard/autolinking.ts"],"names":[],"mappings":"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","sourcesContent":["import { MatchData, Searcher, search } from 'fast-fuzzy'\nimport { FigmaRestApi } from '../figma_rest_api'\nimport path from 'path'\nimport { getComponentOptionsMap } from './helpers'\nimport prompts from 'prompts'\n\nconst FILENAME_MINIMUM_MATCH_THRESHOLD = 0.8\nconst EXPORT_NAME_MINIMUM_MATCH_THRESHOLD = 0.8\n\n/**\n * Guesses which export to use for a given file. Prioritizes default then search term.\n * @param args\n * @param args.filepath current file\n * @param args.exportOptions exported members of current file\n * @param args.nameToMatch name of Figma component\n * @returns filepathExport to use\n */\nexport function getBestMatchingExportWithinFile({\n filepath,\n exportOptions,\n nameToMatch,\n}: {\n filepath: string\n exportOptions: prompts.Choice[]\n nameToMatch: string\n}): string {\n // Don't append export if no known exports\n if (exportOptions.length === 0) {\n return filepath\n }\n\n if (exportOptions.length === 1) {\n return exportOptions[0].value\n }\n const defaultOption = exportOptions.find((o) => o.title === 'default')\n if (defaultOption) {\n return defaultOption.value\n }\n\n const matches = search(\n nameToMatch,\n exportOptions.map((opt) => opt.title),\n {\n threshold: EXPORT_NAME_MINIMUM_MATCH_THRESHOLD,\n },\n )\n\n if (matches.length > 0) {\n /**\n * fuzzy.search searches for string inside another, meaning e.g. \"Button\" and \"ButtonProps\" rank equally for \"Button\".\n * We counter this by looking for shortest string in matches\n */\n const shortestMatch = matches.reduce(function (a, b) {\n return a.length <= b.length ? a : b\n })\n\n if (shortestMatch) {\n return exportOptions.find((o) => o.title === shortestMatch)!.value\n }\n }\n\n // use anything\n return exportOptions[0].value\n}\n\n/**\n * Autolinks components/paths based on fuzzy matching of name and writes mappings to linkedNodeIdsToPaths.\n *\n * Matching is done by fast-fuzzy\n */\nexport function autoLinkComponents({\n unconnectedComponents,\n linkedNodeIdsToFilepathExports,\n filepathExports,\n}: {\n unconnectedComponents: FigmaRestApi.Component[]\n linkedNodeIdsToFilepathExports: Record\n filepathExports: string[]\n}) {\n const componentOptionsMap = getComponentOptionsMap(filepathExports)\n\n const pathMatchScores: Record = {}\n /**\n * fast-fuzzy finds best match in filenames for a given component - this function\n * allows us to replace that link if a closer match is found\n */\n function isBestMatchForPath(match: MatchData) {\n return !pathMatchScores[match.item] || match.score > pathMatchScores[match.item].score\n }\n\n const matchableFilenameToPathMap = Object.keys(componentOptionsMap).reduce(\n (acc, componentPath) => {\n const { name, dir } = path.parse(componentPath)\n // For index.ts files, match on the directory name\n const matchableName = name === 'index' ? path.basename(dir) : name\n acc[matchableName] = componentPath\n return acc\n },\n {} as Record,\n )\n\n const searchSpace = Object.keys(matchableFilenameToPathMap)\n const searcher = new Searcher(searchSpace)\n\n unconnectedComponents.forEach((component) => {\n const matchableName = component.name\n const results = searcher.search(matchableName, { returnMatchData: true })\n const bestMatch = results[0]\n const filename = bestMatch?.item\n if (\n bestMatch &&\n bestMatch.score > FILENAME_MINIMUM_MATCH_THRESHOLD &&\n filename in matchableFilenameToPathMap &&\n isBestMatchForPath(bestMatch)\n ) {\n const filepath = matchableFilenameToPathMap[bestMatch.item]\n linkedNodeIdsToFilepathExports[component.id] = getBestMatchingExportWithinFile({\n filepath,\n exportOptions: componentOptionsMap[filepath],\n nameToMatch: component.name,\n })\n pathMatchScores[bestMatch.item] = { nodeId: component.id, score: bestMatch.score }\n }\n })\n}\n"]}