angularjs-to-react

Migrate an AngularJS codebase to a React codebase

Example

# Example Output React folder
# react-app/
# ├── public/                              # Contains static assets like HTML files, icons, etc.
# │   ├── favicon.ico                      # App icon
# │   ├── index.html                       # Main HTML file
# │   └── manifest.json                    # Manifest file for PWA configuration
# ├── src/
# │   ├── components/                      # Contains all React components.
# │   │   ├── Dashboard.tsx                # Example component
# │   │   ├── UserProfile.tsx              # Example component
# │   │   └── Header.tsx                   # Example component
# │   ├── services/                        # Services for handling API calls and other shared logic.
# │   │   ├── userService.ts               # Example service
# │   │   ├── apiService.ts                # Handles general API interactions
# │   │   └── authService.ts               # Authentication related services
# │   ├── hooks/                           # Custom React hooks.
# │   │   ├── useFetch.ts                  # Hook for API fetching
# │   │   ├── useAuth.ts                   # Authentication hook
# │   │   └── useResponsive.ts             # Responsive design hook
# │   ├── utils/                           # Utility functions.
# │   │   ├── format.ts                    # Formatting utilities
# │   │   ├── validate.ts                  # Validation utilities
# │   │   └── constants/                   # Constants used across the app
# │   │       ├── <constant-name>.ts
# │   │       ├── <constant-name>.ts
# │   │       └── <constant-name>.ts
# │   ├── store/                           # Redux store, reducers, and actions if using Redux.
# │   │   ├── index.ts                     # Combines reducers and configures the store
# │   │   ├── rootReducer.ts               # Root reducer combining all feature reducers
# │   │   ├── user/
# │   │   │   ├── userActions.ts           # Actions for user-related functionality
# │   │   │   ├── userReducer.ts           # Reducer for user-related data
# │   │   │   └── userTypes.ts             # TypeScript types and interfaces for user
# │   │   ├── product/
# │   │   │   ├── productActions.ts        # Actions for product-related functionality
# │   │   │   ├── productReducer.ts        # Reducer for product-related data
# │   │   │   └── productTypes.ts          # TypeScript types and interfaces for product
# │   │   └── settings/
# │   │       ├── settingsActions.ts       # Actions for settings functionality
# │   │       ├── settingsReducer.ts       # Reducer for settings data
# │   │       └── settingsTypes.ts         # TypeScript types and interfaces for settings
# │   ├── assets/                          # Static assets like images, stylesheets, etc.
# │   │   ├── images/                      # Folder for images
# │   │   ├── styles/                      # Folder for CSS or SCSS files
# │   │   └── fonts/                       # Folder for custom fonts
# │   ├── routes/
# │   │   ├── PrivateRoute.tsx             # Component for handling private routes
# │   │   └── Routes.tsx                   # All route definitions in one place
# │   ├── App.tsx                          # Root React component
# │   └── index.tsx                        # Entry point for React application, setup context providers, and Router
# ├── tsconfig.json                        # TypeScript configuration file
# ├── package.json                         # Project metadata and dependencies
# ├── .gitignore                           # Specifies intentionally untracked files to ignore
# └── README.md                            # Project overview and documentation
constants:
  react_directory: 'react'
  src_directory: '{{ react_directory }}/src'
  assets_directory: '{{ src_directory }}/assets'
  entry_file_path: '{{ src_directory }}/App.tsx'
  components_directory: '{{ src_directory }}/components'
  utils_directory: '{{ src_directory }}/utils'
  services_directory: '{{ src_directory }}/services'
  controllers_directory: '{{ components_directory }}/controllers'
  directives_directory: '{{ components_directory }}/directives'
  constants_directory: '{{ utils_directory }}/constants'
  config_directory: '{{ utils_directory }}/config'
  filters_directory: '{{ utils_directory }}/filters'
  context_depth: 3 # The depth of the context to retrieve for each file.
  libraries_to_install:
    - axios
    - react-router-dom
    - react-use

  library_mappings: |
    - All $http and $httpProvider usages should be converted/replaced with the `axios` equivalent.
    - All $location usages should be converted/replaced with the `react-router-dom` equivalent, using the `useLocation` hook.
    - All $scope usages should be converted/replaced with React's state and props.
    - All ng-model usages should be converted/replaced with React's controlled components using the `useState` hook.
    - All ng-repeat usages should be converted/replaced with JavaScript's `map` function in JSX.
    - All ng-if usages should be converted/replaced with conditional rendering in JSX (`{condition && <Component />}`).
    - All ng-show and ng-hide usages should be converted/replaced with conditional rendering in JSX (`{condition ? <Component /> : null}`).
    - All ng-class usages should be converted/replaced with dynamic class names using `className` and template literals.
    - All angular-aria usages should be converted/replaced with React's built-in accessibility features.
    - All angular-loader usages should be converted/replaced with React's built-in lazy loading (`React.lazy` and `Suspense`).
    - All angular-messages usages should be converted/replaced with React's built-in state and conditional rendering.
    - All angular-resource usages should be converted/replaced with the `axios` equivalent.
    - All angular-route usages should be converted/replaced with the `react-router-dom` equivalent.
    - All angular-touch usages should be converted/replaced with React's built-in event handling.

  transformation_notes: |
    ## Codebase Transformation Notes

    ### Generation Preferences
    When generating code, follow these guidelines:
    - Only include information from the portion you were told to convert.
    - Do not create new configs, components, or example usages.
    - Remove AngularJS-specific elements that cannot be converted to React.
    - Leave empty functions as they are.
    - If the current file path was provided above, you should ensure that the import paths are relative to this path.
    - At the top of the converted file, you should include a comment with the original file path. Something like `// Converted from <original-file-path>`.
    - The resulting code should be DRY and only declare one component per file.
    - The resulting code should be written in TypeScript.
    - You should always define and export functions. You should never use the class syntax when defining services, hooks, components or otherwise. Always use functional syntax and prefer projection functions where possible.
    - Do not hallucinate!

    ### Angularjs to React Conversion Guidelines
    - Angular `ng-` directives should be converted to the react-equivalent logic. Do not leave these in the template.
    - Special built-in angularjs services and factories, typically defined as $<service-name>, should be converted to react-equivalent logic.
    - AngularJS injectors are no longer needed in React.

    ### New Files
    When defining new files based on unconverted files, assume the following naming strategies (useful for imports):
    - AngularJS constants -> TypeScript constants in `{{ constants_directory }}/<constant-name>.ts`. Each file will have a single default export that can be imported and used in other files.
    - AngularJS services, factories, and providers -> React services in `{{ services_directory }}/<current-file-name>.tsx`. Each file will have a single default export function that can be imported and used in other files.
    - AngularJS directives -> React components in `{{ directives_directory }}/<current-file-name>.tsx`. Each file will have a single default export function that can be imported and used in other files.
    - AngularJS filters -> React components in `{{ filters_directory }}/<current-file-name>.tsx`. Each file will have a single default export function that can be imported and used in other files.
    - AngularJS controllers and template HTML files -> React components in `{{ controllers_directory }}/<current-file-name>.tsx`. Each file will have a single default export function that can be imported and used in other files.
    - AngularJS config and routes -> React components in `{{ config_directory }}/<current-file-name>.tsx`. Each file will have a single default export function that can be imported and used in other files.

    ### Libraries
    The following libraries are already installed in the project and available for you to use (in addition to the default react libraries): {{ libraries_to_install }}

    #### Mapping Angularjs libraries to React-compatible libraries:
    {{ library_mappings }}

  ignore_file_paths:
    - 'gulpfile.js'
    - 'LICENSE'
    - '**/test/**'
    - 'test/**'
    - 'package.json'
    - '.gitignore'
    - 'tsconfig.json'
    - 'README.md'
    - '**/{{ react_directory }}'
    - '**/{{ react_directory }}/**'
    - '*.config'

  # The HRC reference may do more harm now with embedding_graph.
  dependency_prompt: |
    Acronym Key:
    - SDIF: Symbol Defined In File
    - SDE: Symbol Defined Externally
    - MAP: Mapping
    - HRC: HTML Reference Controller

    You should find all SDIFs, SDEs, HRCs, and MAPs in the file. Below are some hints to help you determine usage, but also rely on your innate knowledge in case the usage is not explicitly stated below.

    You only care about the high level connections between files like definitions for factories, controllers, services, configs, etc. and their dependencies (declared in the brackets after the name of the angular declaration type) as well as mappings of controllers to file paths.

    Rules:
    - If a AngularJS directive is declared in the template, you care about the value the directive is set to, not the directive itself. For example if you have `ng-controller="ExampleCtrl as example"`, you should only care about `ExampleCtrl` and not `ng-controller`.
    - If an Angularjs module is defined in this file, you should return the name of the module as one of the SDIF keys. If it is just used or added to with .controller, .factory, .service, etc, you should include it as a SDE key.
    - You should ALWAYS ignore built-in special angularjs functions, variables, and boilerplate like `$http`, `$timeout`, `.module`, `.controller`, etc. 
    - You should still include $rootScope definitions because it tells us where the global variables are defined.
    - NEVER include standard library variables like window.* or document.*, console.*, etc. when looking for SDIFs or SDEs.
    - When including nested objects, you should AT MOST include 1 level deep. For example, if you have `PageValue.page.title` and `PageValue.page.content`, you should only include `PageValue.page` once as a SDIF or SDE key, even though more deeply nested sub-fields may be present.
    - `directives` defined in js logic should be converted to kebab-case (e.g. `myDirective` -> `my-directive`), then added as a key in either SDIF or SDE.

    ## MAP Example:
    ```
    var routes = {
      "example": {
        controller: 'ExampleCtrl',
        templateUrl: 'example.html'
      }
    // ...
    <div>
      {{ routes }}
    </div>
    ```
    - In the above case, in "routes.example" the controller and template are mapped to each other where the template relies on the controller. 
    - Note that usages of variables, even if defined externally, would not be considered mappings. Mappings should only be used to allow us to map two files together and should NEVER include two symbol types.
    - For now, mappings should ONLY be two paths or a symbol and a path. It should never be a symbol and a symbol.

    ## SDIF Example:
    SDIFs are frequently defined in the controller, service, factory, constant, config, etc. Typically it would look something like `angular.module(...).controller(...);` where controller could be any of the valid angularjs types.
    ```
    angular.module('app').controller('ExampleCtrl', ['$scope', '$http', function($scope, $http) {
      $scope.example = 'example';
      $rootScope.exampleGlobal.example = 'example';
    }]);
    ```
    In the above case, the controller is ExampleCtrl and it is a SDIF, likely to be used in other parts of the application. $scope is used to represent local variables in the controller and therefore shouldn't be included. However, `$rootScope.exampleGlobal.example` should be included as an SDE under the key `$rootScope.exampleGlobal`.

    ## SDE Example:
    SDEs are frequently USED in a controller, service, factory, constant, config, etc.
    ```
    angular.module('app').controller('AnotherCtrl', ['$scope', '$http', function($scope, $http) {
      if ($scope.example) {
        // ...
      }
    }]);
    ```
    In the above case, $scope.example should not be included in either SDE or SDIF because it is local only to this file and the template. In this case though, AnotherCtrl would be returned as a SDIF, `module("app")` would also be included as an SDE".

    ## HRC Example:
    ```
    <div ng-controller="someController as vm" ng-init="vm.getCurrentUser()">
      ....  
    </div>
    ```
    - In the above case, the referenced controller is someController, and it is needed in the template. 
    - This controller should be seen before the template in the dependency graph.

    Be greedy.

steps:
  - name: Create a new React app
    tools:
      - name: create_react_app
        arguments:
          path_to_directory: '{{ react_directory }}'

  - name: Install target conversion libraries
    tools:
      - name: for_each
        items: '{{ libraries_to_install }}'
        each_item:
          item_name: library
          tools:
            - name: run_terminal_command
              arguments:
                path_to_directory: '{{ react_directory }}'
                command: 'npm i {{ library }}'

  - name: Update tsconfig to be stricter
    tools:
      - name: find_files_by_name_with_regex
        arguments:
          find_file_name_pattern: 'tsconfig\.json'
        returns: tsconfig_file_paths
      - name: get_first
        arguments:
          array: '{{ tsconfig_file_paths }}'
        returns: tsconfig_file_path
      - name: edit_json
        arguments:
          path_to_file: '{{ tsconfig_file_path }}'
          json_path: 'compilerOptions'
          action: 'add'
          values:
            - key: 'noUnusedLocals'
              value: true
            - key: 'noUnusedParameters'
              value: true

  - name: Build a dependency graph of the codebase
    tools:
      - name: build_dependency_graph_with_ai
        arguments:
          dependency_prompt: '{{ dependency_prompt }}'
          exclude_path_patterns: '{{ ignore_file_paths }}'

  - name: Convert files in order
    tools:
      - name: get_files_in_topological_order
        arguments:
          top_down: true
        returns: conversion_order_by_level

      - name: for_each
        items: '{{ conversion_order_by_level }}'
        each_item:
          item_name: level
          tools:
            - name: async_each
              items: '{{ level }}'
              each_item:
                item_name: file_to_convert
                tools:
                  - name: get_content_from_file
                    arguments:
                      path_to_file: '{{ file_to_convert }}'
                    returns: file_contents

                  - name: get_file_long_context
                    arguments:
                      path_to_file: '{{ file_to_convert }}'
                      depth: '{{ context_depth }}'
                      graph_type: 'embedding'
                    returns: file_context

                  - name: get_file_name
                    arguments:
                      path_to_file: '{{ file_to_convert }}'
                      include_extension: false
                    returns: file_name

                  - name: switch
                    content: |
                      ## {{ file_to_convert }}
                      ```
                      {{ file_contents }}
                      ```
                    cases:
                      # Update App.tsx
                      - condition_prompt: Is this the root entry point either logic or template for the AngularJS app that should be put into the App.tsx React file?
                        break: true
                        tools:
                          - name: chunk_prompt
                            arguments:
                              contents:
                                - priority: 3
                                  content: '{{ file_context }}'
                                - priority: 2
                                  content: |
                                    Angularjs Code to convert to React ({{ file_to_convert }}):
                                    ```
                                    {{ file_contents }}
                                    ```
                                - priority: 1
                                  content: |
                                    # Instructions
                                    - Extract code from the AngularJS file that should be converted to React.
                                    - Merge that code with the existing content in the file and write out the merged content.
                                    - The only time you can fully replace code is if the code in App.tsx is clearly the dummy text that was generated by create-react-app.
                                    - If the code already looks like it was converted from AngularJS, you should ensure all previous functionality remains along with the new logic that you will implement.
                                    - Do not just concatenate converted parts together, you should rewrite so that the code is DRY without losing functionality.
                                    - If there are no changes to make, return an empty code block (``````).

                                    {{ transformation_notes }}
                            returns: chunked_prompts

                          - name: edit_file_long_context
                            arguments:
                              path_to_file: '{{ entry_file_path }}'
                              edit_prompts: '{{ chunked_prompts }}'

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths:
                                - '{{ entry_file_path }}'

                      # Constant or value
                      - condition_prompt: Does this file contain an Angularjs constant or value definition?
                        tools:
                          - name: find_content_in_file_with_ai
                            arguments:
                              path_to_file: '{{ file_to_convert }}'
                              find_context_prompt: 'Find and return JUST the name of each constant or value defined in the file. If there are none, return an empty array.'
                              results_as_array: true
                            returns: constant_or_value_names
                          - name: async_each
                            items: '{{ constant_or_value_names }}'
                            returns_key: constant_file_path
                            each_item:
                              item_name: constant_or_value_name
                              tools:
                                - name: make_variable
                                  arguments:
                                    value: '{{ constants_directory }}/{{ constant_or_value_name }}.ts'
                                  returns: constant_file_path
                                - name: chunk_prompt
                                  arguments:
                                    contents:
                                      - priority: 3
                                        content: '{{ file_context }}'
                                      - priority: 2
                                        content: |
                                          Angularjs Code ({{ file_to_convert }}):
                                          ```
                                          {{ file_contents }}
                                          ```
                                      - priority: 1
                                        content: |
                                          # Instructions
                                          - Extract `{{ constant_or_value_name }}` from the above AngularJS code and convert it to a TypeScript constant for React components.
                                          - Only extract and convert `{{ constant_or_value_name }}` and it's relevant information to make it work in React on it's own. Ignore anything else.
                                          - The resulting file will be created at {{ constant_file_path }}.
                                          - You should always type the converted angularjs constant or value in TypeScript with the information given. Do not assume new fields, only create a type from the fields you know for certain exist.
                                          - Constants should have a single default export that can be imported and used in other files.

                                          {{ transformation_notes }}
                                  returns: chunked_prompts

                                - name: edit_file_long_context
                                  arguments:
                                    path_to_file: '{{ constant_file_path }}'
                                    edit_prompts: '{{ chunked_prompts }}'

                            # Return from for loop
                            returns: file_paths

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths: '{{ file_paths }}'

                      # Filters
                      - condition_prompt: Does this file contain an Angularjs filter definition?
                        tools:
                          - name: find_content_in_file_with_ai
                            arguments:
                              path_to_file: '{{ file_to_convert }}'
                              find_context_prompt: 'Find and return JUST the name of each filter defined in the file. If there are none, return an empty array.'
                              results_as_array: true
                            returns: filter_names
                          - name: async_each
                            items: '{{ filter_names }}'
                            returns_key: filter_file_path
                            each_item:
                              item_name: filter_name
                              tools:
                                - name: make_variable
                                  arguments:
                                    value: '{{ filters_directory }}/{{ filter_name }}.tsx' # TODO: This should be .ts ideally - sometimes the model gets confused and will include template code in here so this is a hack until we can figure out why.
                                  returns: filter_file_path
                                - name: chunk_prompt
                                  arguments:
                                    contents:
                                      - priority: 3
                                        content: '{{ file_context }}'
                                      - priority: 2
                                        content: |
                                          Angularjs Code ({{ file_to_convert }}):
                                          ```
                                          {{ file_contents }}
                                          ```
                                      - priority: 1
                                        content: |
                                          # Instructions
                                          - Extract `{{ filter_name }}` from the above AngularJS code and convert it to a TypeScript utility function for React components.
                                          - Only extract and convert `{{ filter_name }}` and its relevant information to make it work in React on its own. Ignore anything else.
                                          - The resulting file will be created at {{ filter_file_path }}.

                                          {{ transformation_notes }}
                                  returns: chunked_prompts

                                - name: edit_file_long_context
                                  arguments:
                                    path_to_file: '{{ filter_file_path }}'
                                    edit_prompts: '{{ chunked_prompts }}'

                            # Return from for loop
                            returns: file_paths

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths: '{{ file_paths }}'

                      # Services
                      - condition_prompt: Does this file contain an Angularjs service definition?
                        tools:
                          - name: find_content_in_file_with_ai
                            arguments:
                              path_to_file: '{{ file_to_convert }}'
                              find_context_prompt: 'Find and return JUST the name of each service defined in the file. If there are none, return an empty array.'
                              results_as_array: true
                            returns: service_names
                          - name: async_each
                            items: '{{ service_names }}'
                            returns_key: service_file_path
                            each_item:
                              item_name: service_name
                              tools:
                                - name: make_variable
                                  arguments:
                                    value: '{{ services_directory }}/{{ service_name }}.tsx'
                                  returns: service_file_path
                                - name: chunk_prompt
                                  arguments:
                                    contents:
                                      - priority: 3
                                        content: '{{ file_context }}'
                                      - priority: 2
                                        content: |
                                          Angularjs Code ({{ file_to_convert }}):
                                          ```
                                          {{ file_contents }}
                                          ```
                                      - priority: 1
                                        content: |
                                          # Instructions
                                          - Extract `{{ service_name }}` from the above AngularJS code and convert it to a TypeScript service for React components.
                                          - Only extract and convert `{{ service_name }}` and its relevant information to make it work in React on its own. Ignore anything else.
                                          - The resulting file will be created at {{ service_file_path }}.
                                          - Service files should have a single default export function that can be imported and used in other files.

                                          {{ transformation_notes }}
                                  returns: chunked_prompts

                                - name: edit_file_long_context
                                  arguments:
                                    path_to_file: '{{ service_file_path }}'
                                    edit_prompts: '{{ chunked_prompts }}'

                            # Return from for loop
                            returns: file_paths

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths: '{{ file_paths }}'

                      # Configs
                      - condition_prompt: Does this file contain an Angularjs config definition?
                        tools:
                          - name: find_content_in_file_with_ai
                            arguments:
                              path_to_file: '{{ file_to_convert }}'
                              find_context_prompt: 'Find and return JUST the name of each config defined in the file. If there is no name defined, create one based on the contents of the config. It is critical that the name could be used as a valid file name. If there are none, return an empty array.'
                              results_as_array: true
                            returns: config_names
                          - name: async_each
                            items: '{{ config_names }}'
                            returns_key: config_file_path
                            each_item:
                              item_name: config_name
                              tools:
                                - name: make_variable
                                  arguments:
                                    value: '{{ config_directory }}/{{ config_name }}.tsx'
                                  returns: config_file_path
                                - name: chunk_prompt
                                  arguments:
                                    contents:
                                      - priority: 3
                                        content: '{{ file_context }}'
                                      - priority: 2
                                        content: |
                                          Angularjs Code ({{ file_to_convert }}):
                                          ```
                                          {{ file_contents }}
                                          ```
                                      - priority: 1
                                        content: |
                                          # Instructions
                                          - Extract `{{ config_name }}` from the above AngularJS code and convert it to a TypeScript config for React components.
                                          - Only extract and convert `{{ config_name }}` and its relevant information to make it work in React on its own. Ignore anything else.
                                          - The resulting file will be created at {{ config_file_path }}.

                                          {{ transformation_notes }}
                                  returns: chunked_prompts

                                - name: edit_file_long_context
                                  arguments:
                                    path_to_file: '{{ config_file_path }}'
                                    edit_prompts: '{{ chunked_prompts }}'

                            # Return from for loop
                            returns: file_paths

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths: '{{ file_paths }}'

                      # Directives
                      - condition_prompt: Does this file contain an Angularjs directive definition?
                        tools:
                          - name: find_content_in_file_with_ai
                            arguments:
                              path_to_file: '{{ file_to_convert }}'
                              find_context_prompt: 'Find and return JUST the name of each directive defined in the file. If there are none, return an empty array.'
                              results_as_array: true
                            returns: directive_names
                          - name: async_each
                            items: '{{ directive_names }}'
                            returns_key: directive_file_path
                            each_item:
                              item_name: directive_name
                              tools:
                                - name: make_variable
                                  arguments:
                                    value: '{{ directives_directory }}/{{ directive_name }}.tsx'
                                  returns: directive_file_path
                                - name: chunk_prompt
                                  arguments:
                                    contents:
                                      - priority: 3
                                        content: '{{ file_context }}'
                                      - priority: 2
                                        content: |
                                          Angularjs Code ({{ file_to_convert }}):
                                          ```
                                          {{ file_contents }}
                                          ```
                                      - priority: 1
                                        content: |
                                          # Instructions
                                          - Extract `{{ directive_name }}` from the above AngularJS code and convert it to a TypeScript component for React components.
                                          - Only extract and convert `{{ directive_name }}` and its relevant information to make it work in React on its own. Ignore anything else.
                                          - The resulting file will be created at {{ directive_file_path }}.

                                          {{ transformation_notes }}
                                  returns: chunked_prompts

                                - name: edit_file_long_context
                                  arguments:
                                    path_to_file: '{{ directive_file_path }}'
                                    edit_prompts: '{{ chunked_prompts }}'

                            # Return from for loop
                            returns: file_paths

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths: '{{ file_paths }}'

                      # Controllers
                      - condition_prompt: Does this file contain an Angularjs controller definition?
                        tools:
                          - name: find_content_in_file_with_ai
                            arguments:
                              path_to_file: '{{ file_to_convert }}'
                              find_context_prompt: 'Find and return JUST the name of each controller defined in the file. If there are none, return an empty array.'
                              results_as_array: true
                            returns: controller_names
                          - name: async_each
                            items: '{{ controller_names }}'
                            returns_key: controller_file_path
                            each_item:
                              item_name: controller_name
                              tools:
                                - name: make_variable
                                  arguments:
                                    value: '{{ controllers_directory }}/{{ controller_name }}.tsx'
                                  returns: controller_file_path
                                - name: chunk_prompt
                                  arguments:
                                    contents:
                                      - priority: 3
                                        content: '{{ file_context }}'
                                      - priority: 2
                                        content: |
                                          Angularjs Code ({{ file_to_convert }}):
                                          ```
                                          {{ file_contents }}
                                          ```
                                      - priority: 1
                                        content: |
                                          # Instructions
                                          - Extract `{{ controller_name }}` from the above AngularJS code and convert it to a TypeScript component for React components.
                                          - Only extract and convert `{{ controller_name }}` and its relevant information to make it work in React on its own. Ignore anything else.
                                          - The resulting file will be created at {{ controller_file_path }}.

                                          {{ transformation_notes }}
                                  returns: chunked_prompts

                                - name: edit_file_long_context
                                  arguments:
                                    path_to_file: '{{ controller_file_path }}'
                                    edit_prompts: '{{ chunked_prompts }}'

                            # Return from for loop
                            returns: file_paths

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths: '{{ file_paths }}'

                      # Routes
                      - condition_prompt: Does this file contain Angularjs routes definitions that should be included in the React Router?
                        tools:
                          - name: truncate_prompt
                            arguments:
                              contents:
                                - priority: 3
                                  content: '{{ file_context }}'
                                - priority: 2
                                  content: |
                                    Angularjs Code to convert to React ({{ file_to_convert }}):
                                    ```
                                    {{ file_contents }}
                                    ```
                                - priority: 1
                                  content: |
                                    # Instructions
                                    - Extract the route definition from the above AngularJS code.
                                    - The only code you care about in this file is the route definition and the variables that define it. Ignore all other code.
                                    - Convert the extracted router-related code to use React Router.
                                    - Ensure all previous functionality remains along with the new logic that you implement.
                                    - Do not just concatenate converted parts together, you should rewrite so that the code is DRY without losing functionality. The result should be a valid React Router configuration file.
                                    - If there isn't any code in the angularjs file that could be converted to valid React Router, you should not make any edits to the file - just return an empty string in that case.
                                    - Do not implement anything other than the router. Other logic will be converted in different steps.

                                    {{ transformation_notes }}
                            returns: truncated_prompt

                          - name: edit_file
                            arguments:
                              path_to_file: '{{ config_directory }}/{{ file_name }}.tsx'
                              edit_prompt: '{{ truncated_prompt }}'

                          - name: mark_files_converted_in_context
                            arguments:
                              done_converting: false
                              old_file_path: '{{ file_to_convert }}'
                              new_file_paths:
                                - '{{ config_directory }}/{{ file_name }}.tsx'

                    # Add case for html?
                    default:
                      tools:
                        # TODO: Implement this case
                        - name: echo_one
                          arguments:
                            echo_arg: 'Doing nothing with {{ file_to_convert }}'

                  # This file is done being converted since it has been fully processed by the switch statement (or skipped)
                  - name: mark_files_converted_in_context
                    arguments:
                      done_converting: true
                      old_file_path: '{{ file_to_convert }}'

  - name: Combine Routes into a single file and add to App.tsx
    tools:
      - name: find_files_by_name_with_regex
        arguments:
          path_to_directory: '{{ config_directory }}'
          find_file_name_pattern: '.*'
        returns: config_file_paths

      - name: get_content_from_files
        arguments:
          paths_to_files: '{{ config_file_paths }}'
        returns: config_file_contents

      - name: edit_file
        arguments:
          path_to_file: '{{ entry_file_path }}'
          edit_prompt: |
            Remove all of the boilerplate added by create-react-app from this file. By the end, this should be as bare bones as possible.

      # Update App.tsx with any routes from the config files
      - name: edit_file
        arguments:
          path_to_file: '{{ entry_file_path }}'
          edit_prompt: |
            The below code could contain React Router configuration. You should extract and add any routes directly into the App.tsx file in addition to adding any comments that start with `// Converted from` that are present at the top of the file we are extracting from. Be meticulous and precise. Do not hallucinate.

            ## Example route
            If a config file contains a route like this:
            ```
            // Converted from example/file/path1.js
            // ...
            <Route path="/" element={<Home />} />
            // ...
            ```

            It should be added to the App.tsx file like this:
            ```
            // Converted from example/file/path1.js
            // Converted from example/file/path2.js
            // ... more imports and logic ...
            function App() {
              // ... maybe some more business logic ...
              return (
                <Routes>
                  <Route path="/" element={<Home />} />
                  // ... other routes ...
                </Routes>
              );
            }
            ```

            ## Config Files
            ```
            {{ config_file_contents }}
            ```

      # Delete routes now that they have been extracted into App.tsx
      - name: for_each
        items: '{{ config_file_paths }}'
        each_item:
          item_name: config_file_path
          tools:
            - name: get_content_from_file
              arguments:
                path_to_file: '{{ config_file_path }}'
              returns: content_for_this_config_file
            - name: ask_question
              arguments:
                question_prompt: |
                  Does the following file contain React Router routes in the form `<Route ... />`? Axios requests should be left alone. This should JUST be routes that are rendered in the browser.
                  ```
                  {{ content_for_this_config_file }}
                  ```
              returns: contains_react_routes
            - name: if_else
              condition: '{{ contains_react_routes }}'
              if:
                tools:
                  - name: delete_file_or_folder
                    arguments:
                      path_to_target: '{{ config_file_path }}'

  - name: Copy static assets
    tools:
      - name: find_files_by_name_with_regex
        arguments:
          path_to_directory: 'src'
          find_file_name_pattern: .*\.(css|svg|png|jpg|jpeg|eot|ttf|otf|woff|woff2|gif|bmp|webp|webm|mp3)$
        returns: static_asset_files
      - name: for_each
        items: '{{ static_asset_files }}'
        each_item:
          item_name: static_file
          tools:
            - name: copy_file
              arguments:
                source_path: '{{ static_file }}'
                destination_path: '{{ assets_directory }}/{{ static_file }}'
              returns: copied_file_path

  - name: Add CSS imports to App.tsx
    tools:
      - name: find_files_by_name_with_regex
        arguments:
          path_to_directory: '{{ assets_directory }}'
          find_file_name_pattern: '.*\.css$'
        returns: css_files
      - name: edit_file
        arguments:
          path_to_file: '{{ entry_file_path }}'
          edit_prompt: |
            We are currently looking at this file: `{{ entry_file_path }}`

            Add CSS imports at the top of the file for the following css files: 
            ```
            {{ css_files }}
            ```

  - name: Resolve import paths
    tools:
      - name: resolve_import_paths
        arguments:
          path_to_directory: '{{ react_directory }}'

  - name: Validate TypeScript Project
    tools:
      - name: validate_typescript_project
        arguments:
          max_context_depth: 3
          directory: '{{ react_directory }}'

Last updated