Skip to content

Commit

Permalink
feat: add prop codemod
Browse files Browse the repository at this point in the history
  • Loading branch information
DipperTheDan committed Jan 25, 2021
1 parent d1cd76a commit 1706a21
Show file tree
Hide file tree
Showing 22 changed files with 266 additions and 0 deletions.
7 changes: 7 additions & 0 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ function Cli() {
)
.action((target, command) => runTransform(target, command, program));

program
.command("add-prop <target> <component> <prop> <value>")
.description("adds a new prop and value to the specified component")
.action((target, component, prop, value, command) =>
runTransform(target, command, program, { component, prop, value })
);

program
.command("rename-prop <target> <component> <old> <replacement>")
.description(
Expand Down
46 changes: 46 additions & 0 deletions transforms/add-prop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# add-prop

This universal codemod provides possibility to add any prop to any component.

```diff
- <Component />
+ <Component newProp="info" />

```
## Usage

`npx carbon-codemod add-prop <target> <component-import-path> <prop> <value>`

### Examples

### String
`npx carbon-codemod add-prop src carbon-react/lib/components/button ml "16px"`

```diff
- <Button>Button</Button>
+ <Button ml="16px">Button</Button>
```

### Number
`npx carbon-codemod add-prop src carbon-react/lib/components/button ml 2`

```diff
- <Button>Button</Button>
+ <Button ml={2}>Button</Button>
```

### Boolean - True
`npx carbon-codemod add-prop src carbon-react/lib/components/button hasBorder true`

```diff
- <Button>Button</Button>
+ <Button hasBorder>Button</Button>
```

### Boolean - False
`npx carbon-codemod add-prop src carbon-react/lib/components/button hasBorder false`

```diff
- <Button>Button</Button>
+ <Button hasBorder={false}>Button</Button>
```
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/BooleanFalse.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asFalse = () => <Button />
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/BooleanFalse.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asFalse = () => <Button hasBorder={false} />
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/BooleanTrue.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asTrue = () => <Button />
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/BooleanTrue.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asTrue = () => <Button hasBorder />
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/NoImport.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Wrong Import
import Tile from "carbon-react/lib/components/NotTile";
export default () => <Tile />;
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const App = () => <Button ml="2" />
Empty file.
4 changes: 4 additions & 0 deletions transforms/add-prop/__testfixtures__/Node.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Button from "carbon-react/lib/components/button";
import Link from "carbon-react/lib/components/link";

export const asNode = () => <Button hasLink={<Link />} />
Empty file.
4 changes: 4 additions & 0 deletions transforms/add-prop/__testfixtures__/Number.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Button from "carbon-react/lib/components/button";

export const asNumber = () => <Button />

3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/Number.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asNumber = () => <Button ml={2} />
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/Object.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asObject = () => <Button info={{prop: 1, prop: 2, prop:3}} />
Empty file.
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/String.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asString = () => <Button />
3 changes: 3 additions & 0 deletions transforms/add-prop/__testfixtures__/String.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from "carbon-react/lib/components/button";

export const asString = () => <Button ml="16px" />
89 changes: 89 additions & 0 deletions transforms/add-prop/__tests__/add-prop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import defineTest from "../../../defineTest";

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "ml",
value: 2,
},
"Number"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "ml",
value: "16px",
},
"String"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "hasBorder",
value: true,
},
"BooleanTrue"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "hasBorder",
value: false,
},
"BooleanFalse"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/component",
prop: "newProp",
value: "value",
},
"NoImport"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "ml",
value: "2",
},
"NoTransformRequired"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "hasLink",
value: "test foo bar",
},
"Node"
);

defineTest(
__dirname,
"add-prop",
{
component: "carbon-react/lib/components/button",
prop: "info",
value: "test foo bar",
},
"Object"
);
27 changes: 27 additions & 0 deletions transforms/add-prop/add-prop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Add a prop to a component <Component /> to <Component prop=value/>
*/
import { addAttribute } from "../builder";
import registerMethods from "../registerMethods";

const transformer = (fileInfo, api, options) => {
const j = api.jscodeshift;
registerMethods(j);
const root = j(fileInfo.source);

const { component, prop, value } = options;

const result = addAttribute(component, prop, value)(
fileInfo,
api,
options,
j,
root
);

if (result) {
return root.toSource();
}
};

module.exports = transformer;
57 changes: 57 additions & 0 deletions transforms/builder/addAttribute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const addAttribute = (path, attribute, value) => (
fileInfo,
api,
options,
j,
root
) => {
const components = root.findJSXElementsByImport(path);

// If the component is not imported, skip this file
if (components.size() === 0) {
return;
}
if (!components) {
return false;
}

let didUpdate = false;
components.forEach((component) => {
if (
!j(component.value.openingElement.attributes)
.find(j.JSXIdentifier, { name: attribute })
.size()
) {
if (typeof value === "string") {
component.value.openingElement.attributes.push(
j.jsxAttribute(j.jsxIdentifier(attribute), j.literal(value))
);
didUpdate = true;
}

if (
typeof value === "number" ||
(typeof value === "boolean" && value === false)
) {
component.value.openingElement.attributes.push(
j.jsxAttribute(
j.jsxIdentifier(attribute),
j.jsxExpressionContainer(j.literal(value))
)
);
didUpdate = true;
}

if (typeof value === "boolean" && value === true) {
component.value.openingElement.attributes.push(
j.jsxAttribute(j.jsxIdentifier(attribute))
);
didUpdate = true;
}
}
});

return didUpdate;
};

export default addAttribute;
2 changes: 2 additions & 0 deletions transforms/builder/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import run from "./run";
import renameAttribute from "./renameAttribute";
import removeAttribute from "./removeAttribute";
import addAttribute from "./addAttribute";
import replaceAttributeValue from "./replaceAttributeValue";

module.exports = {
run,
renameAttribute,
removeAttribute,
addAttribute,
replaceAttributeValue,
};

0 comments on commit 1706a21

Please sign in to comment.