Skip to content

Commit

Permalink
Feat(web-react, web-twig): Introduce Codemods
Browse files Browse the repository at this point in the history
- Codemode examples for web-react and web-twig
- Test example for web-react codemod
- #DS-958
  • Loading branch information
pavelklibani committed Feb 5, 2024
1 parent bba9fb3 commit a909559
Show file tree
Hide file tree
Showing 17 changed files with 531 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { Button } from '../../src/components/Button';

export const MyComponent = () => {
return <Button buttonLabel="Click me" />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { Button } from '../../src/components/Button';

export const MyComponent = () => {
return <Button buttonText="Click me" />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { defineTest } = require('jscodeshift/dist/testUtils');

defineTest(__dirname, 'transformAttributeExample', null, 'transformAttributeExample', {
parser: 'tsx',
fixture: 'input',
snapshot: true,
});
10 changes: 10 additions & 0 deletions packages/web-react/transforms/src/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { Button } from '../../src/components/Button';

const testButton = () => {
// should be transformed from buttonLabel to buttonText
// original: <Button id="test" buttonLabel="test" />
return <Button id="test" buttonLabel="test" />;
};

export default testButton;
10 changes: 10 additions & 0 deletions packages/web-react/transforms/src/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { Tooltip } from '../../src/components/Tooltip';

const testTooltip = () => {
// placement should be transformed from top-left to top-start etc.
// original: <Tooltip placement="top-left">tooltip</Tooltip>
return <Tooltip placement="top-left">tooltip</Tooltip>;
};

export default testTooltip;
10 changes: 10 additions & 0 deletions packages/web-react/transforms/src/TooltipModern.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { Tooltip } from '../../src/components/Tooltip';

const testTooltip = () => {
// placement should be transformed from top-left to top-start etc.
// original: <Tooltip>tooltip</Tooltip>;
return <Tooltip>tooltip</Tooltip>;
};

export default testTooltip;
59 changes: 59 additions & 0 deletions packages/web-react/transforms/transformAttributeExample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Install jscodeshift if you haven't already
// npm install -g jscodeshift

// Run with:
// jscodeshift --transform ./transforms/transformAttributeExample.ts --extensions tsx ./transforms/src

// Result:
// Will rename 'text' attribute to 'label' in all Button components imported from '@lmc-eu/spirit-web-react'

const transform = (fileInfo, api) => {
const j = api.jscodeshift;
const root = j(fileInfo.source);

// Find import statements for the specific module and Button specifier
const importStatements = root.find(j.ImportDeclaration, {
source: {
// value: '@lmc-eu/spirit-web-react',
value: '../../src/components/Button', // local import (testing file)
},
});

// Check if the module is imported
if (importStatements.length > 0) {
const buttonSpecifier = importStatements.find(j.ImportSpecifier, {
imported: {
type: 'Identifier',
name: 'Button',
},
});

// Check if Button specifier is present
if (buttonSpecifier.length > 0) {
// Find Button components in the module
const buttonComponents = root.find(j.JSXOpeningElement, {
name: {
type: 'JSXIdentifier',
name: 'Button',
},
});

// Rename 'buttonLabel' attribute to 'buttonText'
buttonComponents
.find(j.JSXAttribute, {
name: {
type: 'JSXIdentifier',
name: 'buttonLabel',
},
})
.forEach((attributePath) => {
// Change attribute name to 'buttonText'
attributePath.node.name.name = 'buttonText';
});
}
}

return root.toSource();
};

export default transform;
70 changes: 70 additions & 0 deletions packages/web-react/transforms/transformComponentNameExample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Install jscodeshift if you haven't already
// npm install -g jscodeshift

// Run with:
// jscodeshift --transform ./transforms/transformComponentNameExample.ts --extensions tsx ./transforms/src

// Result:
// Will change import from Tooltip to TooltipModern in all files where @lmc-eu/spirit-web-react

const transform = (fileInfo, api) => {
const j = api.jscodeshift;
const root = j(fileInfo.source);

// Find import statements for the specific module
const importStatements = root.find(j.ImportDeclaration, {
source: {
// value: '@lmc-eu/spirit-web-react',
value: '../../src/components/Tooltip', // local import (testing file)
},
});

// Check if the module is imported
if (importStatements.length > 0) {
// Update import statement
importStatements.forEach((importPath) => {
const importSpecifiers = importPath.value.specifiers;

// Find the Tooltip import specifier
const tooltipSpecifier = importSpecifiers.find((specifier) => specifier.imported.name === 'Tooltip');

if (tooltipSpecifier) {
// Rename import specifier to 'TooltipModern'
tooltipSpecifier.local.name = 'TooltipModern';

// Update the source value of the import statement
importPath.value.source.value = '../../src/components/TooltipModern';
}
});

// Find opening tags for Tooltip components
root
.find(j.JSXOpeningElement, {
name: {
type: 'JSXIdentifier',
name: 'Tooltip',
},
})
.forEach((tooltipPath) => {
// Change component name to 'TooltipModern'
tooltipPath.node.name.name = 'TooltipModern';
});

// Find closing tags for Tooltip components
root
.find(j.JSXClosingElement, {
name: {
type: 'JSXIdentifier',
name: 'Tooltip',
},
})
.forEach((closingTagPath) => {
// Change closing tag name to 'TooltipModern'
closingTagPath.node.name.name = 'TooltipModern';
});
}

return root.toSource();
};

export default transform;
67 changes: 67 additions & 0 deletions packages/web-react/transforms/transformValueExample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Install jscodeshift if you haven't already
// npm install -g jscodeshift

// Run with:
// jscodeshift --transform ./transforms/transformValueExample.ts --extensions tsx ./transforms/src

// Result:
// Will replace *-left to *-start etc. Tooltip components imported from '@lmc-eu/spirit-web-react'

const transform = (fileInfo, api) => {
const j = api.jscodeshift;
const root = j(fileInfo.source);

// Find import statements for the specific module
const importStatements = root.find(j.ImportDeclaration, {
source: {
// value: '@lmc-eu/spirit-web-react',
value: '../../src/components/Tooltip', // local import (testing file)
},
});

// Check if the module is imported
if (importStatements.length > 0) {
const tooltipSpecifier = importStatements.find(j.ImportSpecifier, {
imported: {
type: 'Identifier',
name: 'Tooltip',
},
});

// Check if Tooltip specifier is present
if (tooltipSpecifier.length > 0) {
// Find Tooltip components in the module
const tooltipComponents = root.find(j.JSXOpeningElement, {
name: {
type: 'JSXIdentifier',
name: 'Tooltip',
},
});

tooltipComponents
.find(j.JSXAttribute, {
name: {
type: 'JSXIdentifier',
name: 'placement',
},
value: {
type: 'Literal',
value: (val) =>
val.includes('-left') || val.includes('-right') || val.includes('-top') || val.includes('-bottom'),
},
})
.forEach((attributePath) => {
// Update attribute value
attributePath.node.value.value = attributePath.node.value.value
.replace('-left', '-start')
.replace('-right', '-end')
.replace('-top', '-start')
.replace('-bottom', '-end');
});
}
}

return root.toSource();
};

export default transform;
81 changes: 81 additions & 0 deletions packages/web-twig/transforms/replace-codemod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Run with:
// node replace-codemod.ts ./src placement

// Result:
// Will replace all strings 'top-left' with 'top-start' in all files in the specified directory (./src)

const fs = require('fs');
const path = require('path');

// Read command-line arguments
const args = process.argv.slice(2);

// Specify the directory where your project files are located
const projectDirectory = args[0];

if (!projectDirectory) {
console.error('Please specify the project directory');
process.exit(1);
}

const codemodName = args[1];

// Define your regex pattern and replacement
switch (codemodName) {
case 'placement':
var pattern = /top-left/g;
var replacement = 'top-start';
break;
case 'buttonText':
var pattern = /buttonLabel/g;
var replacement = 'buttonText';
break;
case 'tooltipModern':
var pattern = /<Tooltip\s*(.*?)\s*>([\s\S]*?)<\/Tooltip>/g;
var replacement = '<TooltipModern $1>$2</TooltipModern>';
break;
default:
console.error('Invalid codemod name');
process.exit(1);
}

// Variables to track the number of changed files
let filesChanged = 0;

// Function to perform regex find and replace in a file
function replaceInFile(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
const newContent = content.replaceAll(pattern, replacement);

// Check if the content has changed
if (content !== newContent) {
fs.writeFileSync(filePath, newContent);
filesChanged++;
}
}

// Function to recursively process files in a directory
function processFiles(directoryPath) {
fs.readdirSync(directoryPath).forEach((file) => {
const filePath = path.join(directoryPath, file);

if (fs.statSync(filePath).isDirectory()) {
// If it's a directory, recursively process its files
processFiles(filePath);
} else {
// If it's a file, perform regex find and replace
replaceInFile(filePath);
}
});
}

// Start processing files in the project directory
processFiles(projectDirectory);

// Log summary
console.log(
`
\x1b[32mReplacement complete.\x1b[0m
${filesChanged} files were changed.
`,
);
2 changes: 2 additions & 0 deletions packages/web-twig/transforms/src/Button.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Button color="primary" buttonLabel="test">Loading button</Button>

3 changes: 3 additions & 0 deletions packages/web-twig/transforms/src/Tooltip.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<TooltipModern placement="top-left">
<Button>button</Button>
</TooltipModern>
1 change: 1 addition & 0 deletions packages/web-twig/transforms/src/TooltipModern.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<TooltipModern >tooltip</TooltipModern>
Loading

0 comments on commit a909559

Please sign in to comment.