Skip to content
67 changes: 67 additions & 0 deletions examples/fragment_to_shorthand/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Transform React Fragment to Shorthand Syntax

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.

> [!NOTE]
> This codemod helps modernize React codebases by using the more concise fragment syntax while maintaining functionality.

## How the Migration Script Works

The script automates the entire conversion process in a few key steps:

1. **Fragment Detection**
```jsx
// From:
<Fragment>
<div>Hello</div>
<div>World</div>
</Fragment>

// To:
<>
<div>Hello</div>
<div>World</div>
</>
```

2. **Import Cleanup**
```typescript
// From:
import React, { Fragment } from 'react';

// To:
import React from 'react';
```

## Why This Makes Migration Easy

1. **Zero Manual Updates**
- Codegen SDK handles all Fragment replacements
- Automatically cleans up imports

2. **Consistent Changes**
- Ensures all Fragments are converted
- Maintains code functionality

3. **Safe Transformations**
- Preserves JSX structure
- Handles nested Fragments correctly

## Running the Migration


The script will:
1. Find all Fragment components
2. Convert them to shorthand syntax
3. Clean up Fragment imports
4. Preserve other React imports

## Learn More

- [React Fragments](https://react.dev/reference/react/Fragment)
- [JSX Fragments](https://react.dev/reference/jsx#jsx-fragments)
- [Codegen Documentation](https://docs.codegen.com)
- [More on Codegen SDK jsx elements API](https://docs.codegen.com/api-reference/typescript/JSXElement#jsxelement)
## Contributing

Feel free to submit issues and enhancement requests!
39 changes: 39 additions & 0 deletions examples/fragment_to_shorthand/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import codegen
from codegen import Codebase
from codegen.sdk.enums import ProgrammingLanguage


@codegen.function("fragment_to_shorthand")
def run(codebase: Codebase):
print("🔍 Starting Fragment syntax conversion...")

for file in codebase.files:
print(f"📁 Processing: {file.filepath}")

fragments_found = False

# Convert Fragment components to shorthand
for element in file.jsx_elements:
if element.name == "Fragment":
print(f"🔄 Converting Fragment in {file.filepath}")
element.set_name("") # Convert to <> syntax
fragments_found = True

# Clean up Fragment imports if we found and converted any
if fragments_found:
for import_stmt in file.import_statements:
for imp in import_stmt.imports:
if imp.name == "Fragment":
print(f"🧹 Removing Fragment import from {file.filepath}")
imp.remove()

if fragments_found:
print(f"✨ Completed conversion in {file.filepath}")
codebase.commit()


if __name__ == "__main__":
print("🎯 Starting Fragment to shorthand conversion...")
codebase = Codebase.from_repo("RocketChat/Rocket.Chat", commit="a4f2102af1c2e875c60cafebd0163105bdaca678", programming_language=ProgrammingLanguage.TYPESCRIPT)
run(codebase)
print("✅ Done! All Fragments converted to shorthand syntax!")
34 changes: 13 additions & 21 deletions examples/reexport_management/run.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import codegen
from codegen import Codebase

from codegen.sdk.typescript.file import TSImport

from codegen.sdk.enums import ProgrammingLanguage

processed_imports = set()


@codegen.function("reexport_management")
def run(codebase: Codebase):
print("🚀 Starting reexport analysis...")
for file in codebase.files:
# Only process files under /src/shared
if "examples/analize_reexports" not in file.filepath or '/src/shared' not in file.filepath:
if "examples/analize_reexports" not in file.filepath or "/src/shared" not in file.filepath:
continue

print(f"📁 Analyzing: {file.filepath}")

# Gather all reexports that are not external exports
all_reexports = []
for export_stmt in file.export_statements:
Expand All @@ -34,10 +38,7 @@ def run(codebase: Codebase):
print(f"🔄 Processing: {export.name} -> {resolved_public_file}")

# Get relative path from the "public" file back to the original file
relative_path = codebase.get_relative_path(
from_file=resolved_public_file,
to_file=export.resolved_symbol.filepath
)
relative_path = codebase.get_relative_path(from_file=resolved_public_file, to_file=export.resolved_symbol.filepath)

# Ensure the "public" file exists
if not codebase.has_file(resolved_public_file):
Expand Down Expand Up @@ -69,14 +70,9 @@ def run(codebase: Codebase):
print(f"📝 Updated existing type export for {export.name}")
else:
if export.is_aliased():
target_file.insert_before(
f'export type {{ {export.resolved_symbol.name} as {export.name} }} '
f'from "{relative_path}"'
)
target_file.insert_before(f'export type {{ {export.resolved_symbol.name} as {export.name} }} from "{relative_path}"')
else:
target_file.insert_before(
f'export type {{ {export.name} }} from "{relative_path}"'
)
target_file.insert_before(f'export type {{ {export.name} }} from "{relative_path}"')
print(f"✨ Added new type export for {export.name}")

# C) Normal export
Expand All @@ -90,14 +86,9 @@ def run(codebase: Codebase):
print(f"📝 Updated existing export for {export.name}")
else:
if export.is_aliased():
target_file.insert_before(
f'export {{ {export.resolved_symbol.name} as {export.name} }} '
f'from "{relative_path}"'
)
target_file.insert_before(f'export {{ {export.resolved_symbol.name} as {export.name} }} from "{relative_path}"')
else:
target_file.insert_before(
f'export {{ {export.name} }} from "{relative_path}"'
)
target_file.insert_before(f'export {{ {export.name} }} from "{relative_path}"')
print(f"✨ Added new export for {export.name}")

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


if __name__ == "__main__":
print("🎯 Starting reexport organization...")
codebase = Codebase("./", programming_language=ProgrammingLanguage.TYPESCRIPT)
Expand Down