-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update svgr codemod to output TS for tsx inputs #8935
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import type { SVGProps } from "react"; | ||
const Kitten1 = (props: SVGProps<SVGSVGElement>) => <svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" {...props}><path fillRule="evenodd" d="M10 2v0c-.56 0-1 .44-1 1v1 0c0 .55.44 1 1 1 .55 0 1-.45 1-1V3v0c0-.56-.45-1-1-1ZM4 4h3v0c0 1.65 1.34 3 3 3 1.65 0 3-1.35 3-3h3v0c1.1 0 2 .89 2 2v9 0c0 1.1-.9 2-2 2H4v0c-1.11 0-2-.9-2-2V6v0c0-1.11.89-2 2-2Zm2.5 7v0c.82 0 1.5-.68 1.5-1.5C8 8.67 7.32 8 6.5 8v0C5.67 8 5 8.67 5 9.5c0 .82.67 1.5 1.5 1.5Zm2.45 4v0c.27-1.36-.6-2.68-1.96-2.95 -1.36-.28-2.68.59-2.95 1.95 -.07.32-.07.66 0 .99h4.9ZM12 9v0c-.56 0-1 .44-1 1 0 .55.44 1 1 1h3v0c.55 0 1-.45 1-1 0-.56-.45-1-1-1h-3Zm-1 4v0c0-.56.44-1 1-1h2v0c.55 0 1 .44 1 1 0 .55-.45 1-1 1h-2v0c-.56 0-1-.45-1-1Z" /></svg>; | ||
export default Kitten1; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import type { SVGProps } from "react"; | ||
const Logo = (props: SVGProps<SVGSVGElement>) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" {...props}><path fillRule="evenodd" d="M6.707 4.879A3 3 0 018.828 4H15a3 3 0 013 3v6a3 3 0 01-3 3H8.828a3 3 0 01-2.12-.879l-4.415-4.414a1 1 0 010-1.414l4.414-4.414zm4 2.414a1 1 0 00-1.414 1.414L10.586 10l-1.293 1.293a1 1 0 101.414 1.414L12 11.414l1.293 1.293a1 1 0 001.414-1.414L13.414 10l1.293-1.293a1 1 0 00-1.414-1.414L12 8.586l-1.293-1.293z" clipRule="evenodd" /></svg>; | ||
export default Logo; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import type { SVGProps } from "react"; | ||
const Kitten1WithDashes = (props: SVGProps<SVGSVGElement>) => <svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" {...props}><path fillRule="evenodd" d="M10 2v0c-.56 0-1 .44-1 1v1 0c0 .55.44 1 1 1 .55 0 1-.45 1-1V3v0c0-.56-.45-1-1-1ZM4 4h3v0c0 1.65 1.34 3 3 3 1.65 0 3-1.35 3-3h3v0c1.1 0 2 .89 2 2v9 0c0 1.1-.9 2-2 2H4v0c-1.11 0-2-.9-2-2V6v0c0-1.11.89-2 2-2Zm2.5 7v0c.82 0 1.5-.68 1.5-1.5C8 8.67 7.32 8 6.5 8v0C5.67 8 5 8.67 5 9.5c0 .82.67 1.5 1.5 1.5Zm2.45 4v0c.27-1.36-.6-2.68-1.96-2.95 -1.36-.28-2.68.59-2.95 1.95 -.07.32-.07.66 0 .99h4.9ZM12 9v0c-.56 0-1 .44-1 1 0 .55.44 1 1 1h3v0c.55 0 1-.45 1-1 0-.56-.45-1-1-1h-3Zm-1 4v0c0-.56.44-1 1-1h2v0c.55 0 1 .44 1 1 0 .55-.45 1-1 1h-2v0c-.56 0-1-.45-1-1Z" /></svg>; | ||
export default Kitten1WithDashes; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import type { SVGProps } from "react"; | ||
const Logo = (props: SVGProps<SVGSVGElement>) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" {...props}><path fillRule="evenodd" d="M6.707 4.879A3 3 0 018.828 4H15a3 3 0 013 3v6a3 3 0 01-3 3H8.828a3 3 0 01-2.12-.879l-4.415-4.414a1 1 0 010-1.414l4.414-4.414zm4 2.414a1 1 0 00-1.414 1.414L10.586 10l-1.293 1.293a1 1 0 101.414 1.414L12 11.414l1.293 1.293a1 1 0 001.414-1.414L13.414 10l1.293-1.293a1 1 0 00-1.414-1.414L12 8.586l-1.293-1.293z" clipRule="evenodd" /></svg>; | ||
export default Logo; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,19 @@ import { transform as svgrTransform } from '@svgr/core' | |
import type { API, FileInfo, StringLiteral } from 'jscodeshift' | ||
import pascalcase from 'pascalcase' | ||
|
||
import { getPaths } from '@redwoodjs/project-config' | ||
|
||
/** | ||
* @param svgFilePath Full path to the existing svg file | ||
* @param outputPath Full path to the output file | ||
* @param componentName Name of the React component to generate inside the output file | ||
* @param typescript Whether to generate TypeScript code | ||
*/ | ||
async function convertSvgToReactComponent( | ||
svgFilePath: string, | ||
outputPath: string, | ||
componentName: string | ||
componentName: string, | ||
typescript: boolean | ||
) { | ||
const svgContents = await fs.readFile(svgFilePath, 'utf-8') | ||
|
||
|
@@ -17,6 +26,7 @@ async function convertSvgToReactComponent( | |
{ | ||
jsxRuntime: 'automatic', | ||
plugins: ['@svgr/plugin-jsx'], | ||
typescript, | ||
}, | ||
{ | ||
componentName: componentName, | ||
|
@@ -25,16 +35,16 @@ async function convertSvgToReactComponent( | |
|
||
await fs.writeFile(outputPath, jsCode) | ||
|
||
console.log() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra blank line needed for Listr to not mess up the output |
||
console.log(`SVG converted to React component: ${outputPath}`) | ||
} | ||
|
||
export default async function transform(file: FileInfo, api: API) { | ||
const j = api.jscodeshift | ||
|
||
const root = j(file.source) | ||
|
||
// Do this lazily | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The cost of importing |
||
const { getPaths } = await import('@redwoodjs/project-config') | ||
// If the input file is TypeScript, we'll generate TypeScript SVG components | ||
const isTS = file.path.endsWith('.tsx') | ||
|
||
// Find all import declarations with "*.svg" import | ||
const svgImports = root.find(j.ImportDeclaration).filter((path) => { | ||
|
@@ -46,6 +56,7 @@ export default async function transform(file: FileInfo, api: API) { | |
filePath: string | ||
importSourcePath: StringLiteral | ||
}> = [] | ||
|
||
// Process each import declaration | ||
svgImports.forEach((importDeclaration) => { | ||
const importSpecifiers = importDeclaration.node.specifiers | ||
|
@@ -99,10 +110,10 @@ export default async function transform(file: FileInfo, api: API) { | |
if (svgsToConvert.length > 0) { | ||
// if there are any svgs used as components, or render props, convert the svg to a react component | ||
await Promise.all( | ||
svgsToConvert.map(async ({ filePath, importSourcePath }) => { | ||
svgsToConvert.map(async (svg) => { | ||
const svgFileNameWithoutExtension = path.basename( | ||
filePath, | ||
path.extname(filePath) | ||
svg.filePath, | ||
path.extname(svg.filePath) | ||
) | ||
|
||
const componentName = pascalcase(svgFileNameWithoutExtension) | ||
|
@@ -111,15 +122,20 @@ export default async function transform(file: FileInfo, api: API) { | |
|
||
// The absolute path to the new file | ||
const outputPath = path.join( | ||
path.dirname(filePath), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reading this code in isolation it was hard to know what This change hopefully makes it more clear that it's the path to the svg file the code is importing |
||
`${newFileName}.jsx` | ||
path.dirname(svg.filePath), | ||
`${newFileName}.${isTS ? 'tsx' : 'jsx'}` | ||
) | ||
|
||
try { | ||
await convertSvgToReactComponent(filePath, outputPath, componentName) | ||
await convertSvgToReactComponent( | ||
svg.filePath, | ||
outputPath, | ||
componentName, | ||
isTS | ||
) | ||
} catch (error: any) { | ||
console.error( | ||
`Error converting ${filePath} to React component: ${error.message}` | ||
`Error converting ${svg.filePath} to React component: ${error.message}` | ||
) | ||
|
||
// Don't proceed if SVGr fails | ||
|
@@ -129,8 +145,8 @@ export default async function transform(file: FileInfo, api: API) { | |
// If SVGr is successful, change the import path | ||
// '../../bazinga.svg' -> '../../BazingaSVG' | ||
// Use extname, incase ext casing does not match | ||
importSourcePath.value = importSourcePath.value.replace( | ||
`${svgFileNameWithoutExtension}${path.extname(filePath)}`, | ||
svg.importSourcePath.value = svg.importSourcePath.value.replace( | ||
`${svgFileNameWithoutExtension}${path.extname(svg.filePath)}`, | ||
newFileName | ||
) | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This, together with the
const isTS =
code below is the main change for this PR.The rest is mostly changes to make the code easier to read and understand