Skip to content

Commit 1438f80

Browse files
authored
Example react modernization (#42)
* . * . * . * . * . * . * . * . * . * . * . * . * . * . * . * . * . * . * Adds fragment to shorthand example * Automated pre-commit update --------- Co-authored-by: kopekC <28070492+kopekC@users.noreply.github.com>
1 parent bf8514e commit 1438f80

File tree

3 files changed

+119
-21
lines changed

3 files changed

+119
-21
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Transform React Fragment to Shorthand Syntax
2+
3+
This example demonstrates how to use Codegen to automatically convert React Fragment components to the shorthand syntax (<>). The script makes this process simple by handling all the tedious manual updates automatically.
4+
5+
> [!NOTE]
6+
> This codemod helps modernize React codebases by using the more concise fragment syntax while maintaining functionality.
7+
8+
## How the Migration Script Works
9+
10+
The script automates the entire conversion process in a few key steps:
11+
12+
1. **Fragment Detection**
13+
```jsx
14+
// From:
15+
<Fragment>
16+
<div>Hello</div>
17+
<div>World</div>
18+
</Fragment>
19+
20+
// To:
21+
<>
22+
<div>Hello</div>
23+
<div>World</div>
24+
</>
25+
```
26+
27+
2. **Import Cleanup**
28+
```typescript
29+
// From:
30+
import React, { Fragment } from 'react';
31+
32+
// To:
33+
import React from 'react';
34+
```
35+
36+
## Why This Makes Migration Easy
37+
38+
1. **Zero Manual Updates**
39+
- Codegen SDK handles all Fragment replacements
40+
- Automatically cleans up imports
41+
42+
2. **Consistent Changes**
43+
- Ensures all Fragments are converted
44+
- Maintains code functionality
45+
46+
3. **Safe Transformations**
47+
- Preserves JSX structure
48+
- Handles nested Fragments correctly
49+
50+
## Running the Migration
51+
52+
53+
The script will:
54+
1. Find all Fragment components
55+
2. Convert them to shorthand syntax
56+
3. Clean up Fragment imports
57+
4. Preserve other React imports
58+
59+
## Learn More
60+
61+
- [React Fragments](https://react.dev/reference/react/Fragment)
62+
- [JSX Fragments](https://react.dev/reference/jsx#jsx-fragments)
63+
- [Codegen Documentation](https://docs.codegen.com)
64+
- [More on Codegen SDK jsx elements API](https://docs.codegen.com/api-reference/typescript/JSXElement#jsxelement)
65+
## Contributing
66+
67+
Feel free to submit issues and enhancement requests!

examples/fragment_to_shorthand/run.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import codegen
2+
from codegen import Codebase
3+
from codegen.sdk.enums import ProgrammingLanguage
4+
5+
6+
@codegen.function("fragment_to_shorthand")
7+
def run(codebase: Codebase):
8+
print("🔍 Starting Fragment syntax conversion...")
9+
10+
for file in codebase.files:
11+
print(f"📁 Processing: {file.filepath}")
12+
13+
fragments_found = False
14+
15+
# Convert Fragment components to shorthand
16+
for element in file.jsx_elements:
17+
if element.name == "Fragment":
18+
print(f"🔄 Converting Fragment in {file.filepath}")
19+
element.set_name("") # Convert to <> syntax
20+
fragments_found = True
21+
22+
# Clean up Fragment imports if we found and converted any
23+
if fragments_found:
24+
for import_stmt in file.import_statements:
25+
for imp in import_stmt.imports:
26+
if imp.name == "Fragment":
27+
print(f"🧹 Removing Fragment import from {file.filepath}")
28+
imp.remove()
29+
30+
if fragments_found:
31+
print(f"✨ Completed conversion in {file.filepath}")
32+
codebase.commit()
33+
34+
35+
if __name__ == "__main__":
36+
print("🎯 Starting Fragment to shorthand conversion...")
37+
codebase = Codebase.from_repo("RocketChat/Rocket.Chat", commit="a4f2102af1c2e875c60cafebd0163105bdaca678", programming_language=ProgrammingLanguage.TYPESCRIPT)
38+
run(codebase)
39+
print("✅ Done! All Fragments converted to shorthand syntax!")

examples/reexport_management/run.py

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import codegen
22
from codegen import Codebase
3+
34
from codegen.sdk.typescript.file import TSImport
5+
46
from codegen.sdk.enums import ProgrammingLanguage
57

68
processed_imports = set()
9+
10+
711
@codegen.function("reexport_management")
812
def run(codebase: Codebase):
913
print("🚀 Starting reexport analysis...")
1014
for file in codebase.files:
1115
# Only process files under /src/shared
12-
if "examples/analize_reexports" not in file.filepath or '/src/shared' not in file.filepath:
16+
if "examples/analize_reexports" not in file.filepath or "/src/shared" not in file.filepath:
1317
continue
14-
18+
1519
print(f"📁 Analyzing: {file.filepath}")
16-
20+
1721
# Gather all reexports that are not external exports
1822
all_reexports = []
1923
for export_stmt in file.export_statements:
@@ -34,10 +38,7 @@ def run(codebase: Codebase):
3438
print(f"🔄 Processing: {export.name} -> {resolved_public_file}")
3539

3640
# Get relative path from the "public" file back to the original file
37-
relative_path = codebase.get_relative_path(
38-
from_file=resolved_public_file,
39-
to_file=export.resolved_symbol.filepath
40-
)
41+
relative_path = codebase.get_relative_path(from_file=resolved_public_file, to_file=export.resolved_symbol.filepath)
4142

4243
# Ensure the "public" file exists
4344
if not codebase.has_file(resolved_public_file):
@@ -69,14 +70,9 @@ def run(codebase: Codebase):
6970
print(f"📝 Updated existing type export for {export.name}")
7071
else:
7172
if export.is_aliased():
72-
target_file.insert_before(
73-
f'export type {{ {export.resolved_symbol.name} as {export.name} }} '
74-
f'from "{relative_path}"'
75-
)
73+
target_file.insert_before(f'export type {{ {export.resolved_symbol.name} as {export.name} }} from "{relative_path}"')
7674
else:
77-
target_file.insert_before(
78-
f'export type {{ {export.name} }} from "{relative_path}"'
79-
)
75+
target_file.insert_before(f'export type {{ {export.name} }} from "{relative_path}"')
8076
print(f"✨ Added new type export for {export.name}")
8177

8278
# C) Normal export
@@ -90,14 +86,9 @@ def run(codebase: Codebase):
9086
print(f"📝 Updated existing export for {export.name}")
9187
else:
9288
if export.is_aliased():
93-
target_file.insert_before(
94-
f'export {{ {export.resolved_symbol.name} as {export.name} }} '
95-
f'from "{relative_path}"'
96-
)
89+
target_file.insert_before(f'export {{ {export.resolved_symbol.name} as {export.name} }} from "{relative_path}"')
9790
else:
98-
target_file.insert_before(
99-
f'export {{ {export.name} }} from "{relative_path}"'
100-
)
91+
target_file.insert_before(f'export {{ {export.name} }} from "{relative_path}"')
10192
print(f"✨ Added new export for {export.name}")
10293

10394
# Update import usages
@@ -131,6 +122,7 @@ def run(codebase: Codebase):
131122
print(f"🧹 Removed empty file: {file.filepath}")
132123
codebase.commit()
133124

125+
134126
if __name__ == "__main__":
135127
print("🎯 Starting reexport organization...")
136128
codebase = Codebase("./", programming_language=ProgrammingLanguage.TYPESCRIPT)

0 commit comments

Comments
 (0)