Skip to content
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

Merged
merged 2 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

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
Expand Up @@ -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')

Expand All @@ -17,6 +26,7 @@ async function convertSvgToReactComponent(
{
jsxRuntime: 'automatic',
plugins: ['@svgr/plugin-jsx'],
typescript,
Copy link
Member Author

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

},
{
componentName: componentName,
Expand All @@ -25,16 +35,16 @@ async function convertSvgToReactComponent(

await fs.writeFile(outputPath, jsCode)

console.log()
Copy link
Member Author

Choose a reason for hiding this comment

The 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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cost of importing getPaths has already been paid by replaceComponentSvgs.yargs.ts, so moved this to a regular import, so you don't have to wonder why we're doing a lazy import.

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) => {
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this code in isolation it was hard to know what filePath was. Path to the file we're parsing? Path to the svg we found in that file? Path to the file we're going to generate?

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
Expand All @@ -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
)
})
Expand Down