andyl / rfx

Refactoring Operations for Elixir

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rfx : ReFactor Elixir

Rfx provides a catalog of automated refactoring operations for Elixir source code.

Rfx operations are meant to be embedded into editors, tools and end-user apps. See the experimental rfxi for an example app. Rfx depends on the excellent Sourceror to manipulate AST code and comments.

To get started with this pre-release code, clone the repo, then run > mix test. NOTE this code is under heavy development - expect rapid changes and bugs!

Ops Modules

See Rfx.Catalog.OpsCat for a live catalog of Operations.

Module Operations:

  • rename module (Rfx.Ops.Module.RenameModule)
  • rename module attribute
  • extract function
  • inline function

Function Operations:

  • rename function
  • rename function parameter
  • rename variable
  • extract variable
  • inline variable

Filesystem Operations:

  • move directory (Rfx.Ops.Filesys.MvDir)
  • move file (Rfx.Ops.Filesys.MvFile)

Credo Operations:

  • multi-alias (Rfx.Ops.Credo.MultiAlias)

Surface Operations:

  • rename component
  • rename property
  • rename named-slot

PhxGen Operations:

  • add route
  • add controller

Project Operations:

  • add dependency
  • increment version

Prototype Operations:

  • comment add (Rfx.Ops.Proto.CommentAdd)
  • comment del (Rfx.Ops.Proto.CommentDel)
  • no-op (Rfx.Ops.Proto.NoOp)

Change Sets

Each operation returns a change set (Rfx.Change.Set) with a list of of change requests (Rfx.Change.Request). The change set is a data structure that describes all the refactoring changes to be made for an operation.

A change request struct has elements for text edits and file actions (create, rename, delete).

Converter Functions

Rfx provides an extensible catalog of converter functions:

Rfx.Change.Set.convert(changeset, :to_string)    #> Returns the modified source code
Rfx.Change.Set.convert(changeset, :to_patchfile) #> Returns a unix-standard patchfile
Rfx.Change.Set.convert(changeset, :to_lsp)       #> Returns a data structure for LSP
Rfx.Change.Set.convert(changeset, :to_pr)        #> Returns a pull-request data structure

Rfx also provides a function that applies the change requests to the filesystem.

Rfx.Change.Set.apply!(changeset)                 #> Applies the changereqs to the filesystem

Code Organization

Each operation is coded in a standalone module that implements the Rfx.Ops behavior. A refactoring operation may be applied to different scopes:

  • Scope1: a code string
  • Scope2: a single file
  • Scope3: an entire project
  • Scope4: an umbrella sub-application
  • Scope5: a temp file

Each scope will generate a different set of change requests. Consider for example the operation Rfx.Ops.Module.RenameModule.

Rename_Module # of Change Requests Text Edits File Actions
Scope1 code 1 Edit src & docs NA
Scope2 file 1 Edit src & docs Rename Src file
Scope3 project 1 for each related project file Edit src & docs Rename Src & Test file
Scope4 subapp 1 for each related subapp file Edit src & docs Rename Src & Test file
Scope5 tmpfile 1 Edit src & docs NA

Here's a code example:

#!/usr/bin/env elixir

Mix.install([ {:rfx, github: "andyl/rfx"} ])

"x = 1"
|> Rfx.Ops.Proto.CommentAdd.cl_code()
|> Rfx.Change.Set.convert(:to_string)
|> IO.inspect()

# [
#   %Rfx.Change.Request{
#     file_req: nil,
#     text_req: %{diff: "0a1\n> # TestComment\n", input_text: "x = 1"},
#     log: %{convert: %{to_string: "# TestComment\nx = 1"}}
#   }
# ]

Clients

Rfx Operations are intended for use in developer tools:

  • Elixir Scripts and Livebooks (examples in rfx/scripts and rfx/notebooks)
  • CLI (see the experimental rfxi)
  • Editor Plugins (see the experimental rfx_nvim)
  • Generators and Mix tasks
  • ElixirLs
  • Credo

Installation

def deps do
  [
    {:rfx, github: "andyl/rfx"}
  ]
end

About

Refactoring Operations for Elixir

License:MIT License


Languages

Language:Elixir 98.1%Language:Shell 1.9%