Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 45 additions & 55 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Created with GitHubActions version 0.2.27
# Created with GitHubActions version 0.3.6
name: CI
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -8,60 +8,35 @@ on:
jobs:
linux:
name: Test on Ubuntu (Elixir ${{ matrix.elixir }}, OTP ${{ matrix.otp }})
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
elixir:
- '1.13.4'
- '1.14.5'
- '1.15.8'
- '1.16.3'
- '1.17.3'
- '1.18.0'
otp:
- '22.3'
- '23.3'
- '24.3'
- '25.3'
- '26.2'
- '27.2'
exclude:
- elixir: '1.13.4'
include:
- elixir: '1.18.4'
otp: '28.1'
coverage: true
lint: true
- elixir: '1.18.4'
otp: '27.3'
- elixir: '1.18.4'
otp: '26.2'
- elixir: '1.13.4'
otp: '27.2'
- elixir: '1.14.5'
otp: '22.3'
- elixir: '1.14.5'
otp: '27.2'
- elixir: '1.15.8'
otp: '22.3'
- elixir: '1.15.8'
otp: '23.3'
- elixir: '1.15.8'
otp: '27.2'
- elixir: '1.16.3'
otp: '22.3'
- elixir: '1.16.3'
otp: '23.3'
- elixir: '1.16.3'
otp: '27.2'
- elixir: '1.17.3'
otp: '22.3'
- elixir: '1.17.3'
otp: '23.3'
- elixir: '1.18.4'
otp: '25.3'
- elixir: '1.17.3'
otp: '25.3'
- elixir: '1.16.3'
otp: '24.3'
- elixir: '1.18.0'
otp: '22.3'
- elixir: '1.18.0'
otp: '23.3'
- elixir: '1.18.0'
- elixir: '1.15.8'
otp: '24.3'
- elixir: '1.14.5'
otp: '24.3'
- elixir: '1.13.4'
otp: '24.3'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Elixir
id: setup-beam
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
Expand All @@ -70,39 +45,54 @@ jobs:
uses: actions/cache@v4
with:
path: deps
key: deps-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
key: "deps\
-${{ runner.os }}\
-${{ matrix.elixir }}\
-${{ matrix.otp }}\
-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}\
-${{ steps.setup-beam.outputs.setup-beam-version }}"
- name: Restore _build
uses: actions/cache@v4
with:
path: _build
key: _build-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
key: "_build\
-${{ runner.os }}\
-${{ matrix.elixir }}\
-${{ matrix.otp }}\
-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}\
-${{ steps.setup-beam.outputs.setup-beam-version }}"
- name: Restore test/support/plts
if: ${{ matrix.lint }}
uses: actions/cache@v4
with:
path: test/support/plts
key: test/support/plts-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
if: ${{ contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2') }}
key: "test/support/plts\
-${{ runner.os }}\
-${{ matrix.elixir }}\
-${{ matrix.otp }}\
-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}\
-${{ steps.setup-beam.outputs.setup-beam-version }}"
- name: Get dependencies
run: mix deps.get
- name: Compile dependencies
run: MIX_ENV=test mix deps.compile
- name: Compile project
run: MIX_ENV=test mix compile --warnings-as-errors
- name: Check unused dependencies
if: ${{ contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2') }}
if: ${{ matrix.lint }}
run: mix deps.unlock --check-unused
- name: Check code format
if: ${{ contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2') }}
if: ${{ matrix.lint }}
run: mix format --check-formatted
- name: Lint code
if: ${{ contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2') }}
if: ${{ matrix.lint }}
run: mix credo --strict
- name: Run tests
if: ${{ !matrix.coverage }}
run: mix test
if: ${{ !(contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2')) }}
- name: Run tests with coverage
if: ${{ matrix.coverage }}
run: mix coveralls.github
if: ${{ contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2') }}
- name: Static code analysis
if: ${{ matrix.lint }}
run: mix dialyzer --format github --force-check
if: ${{ contains(matrix.elixir, '1.18.0') && contains(matrix.otp, '27.2') }}
99 changes: 49 additions & 50 deletions lib/rewrite.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ defmodule Rewrite do
@moduledoc """
`Rewrite` is a tool for modifying, adding and removing files in a `Mix` project.

The package is intended for use in `Mix` tasks. `Rewrite` itself uses functions
provided by `Mix`.
The package is intended for use in `Mix` tasks. `Rewrite` itself uses functions
provided by `Mix`.

With `Rewrite.read!/2` you can load the whole project. Then you can modify the
project with a number of functions provided by `Rewrite` and `Rewrite.Source`
without writing any changes back to the file system. All changes are stored in
the source structs. Any version of a source is available in the project. To
With `Rewrite.read!/2` you can load the whole project. Then you can modify the
project with a number of functions provided by `Rewrite` and `Rewrite.Source`
without writing any changes back to the file system. All changes are stored in
the source structs. Any version of a source is available in the project. To
write the whole project back to the file system, the `Rewrite.write_all/2` can
be used.

Elixir source files can be modified by modifying the AST. For this `Rewrite`
Elixir source files can be modified by modifying the AST. For this `Rewrite`
uses the `Sourceror` package to create the AST and to convert it back. The
`Sourceror` package also provides all the utilities needed to manipulate the
AST.

Sources can also receive a `Rewrite.Issue` to document problems or information
with the source.
Sources can also receive a `Rewrite.Issue` to document problems or information
with the source.

`Rewrite` respects the `.formatter.exs` in the project when rewriting sources.
To do this, the formatter can be read by `Rewrite.DotFormatter` and the
resulting DotFormatter struct can be used in the function to update the
`Rewrite` respects the `.formatter.exs` in the project when rewriting sources.
To do this, the formatter can be read by `Rewrite.DotFormatter` and the
resulting DotFormatter struct can be used in the function to update the
sources.
"""

Expand Down Expand Up @@ -58,10 +58,10 @@ defmodule Rewrite do

## Options

* `:filetypes` - a list of modules implementing the behavior
`Rewrite.Filetype`. This list is used to add the `filetype` to the
`sources` of the corresponding files. The list can contain modules
representing a file type or a tuple of `{module(), keyword()}`. Rewrite
* `:filetypes` - a list of modules implementing the behavior
`Rewrite.Filetype`. This list is used to add the `filetype` to the
`sources` of the corresponding files. The list can contain modules
representing a file type or a tuple of `{module(), keyword()}`. Rewrite
uses the keyword list from the tuple as the options argument when a file
is read.

Expand Down Expand Up @@ -105,9 +105,9 @@ defmodule Rewrite do

* Accepts the same options as `new/1`.

* 'exclude' - a list of paths and/or glob expressions to exclude sources
from the project. The option also accepts a predicate function which is
called for each source path. The exclusion takes place before the file is
* 'exclude' - a list of paths and/or glob expressions to exclude sources
from the project. The option also accepts a predicate function which is
called for each source path. The exclusion takes place before the file is
read.
"""
@spec new!(input() | [input()], opts) :: t()
Expand All @@ -122,12 +122,12 @@ defmodule Rewrite do
## Options

* `:force`, default: `false` - forces the reading of sources. With
`force: true` updates and issues for an already existing source are
`force: true` updates and issues for an already existing source are
deleted.

* `:exclude` - a list of paths and/or glob expressions to exclude sources
from the project. The option also accepts a predicate function which is
called for each source path. The exclusion takes place before the file is
* `:exclude` - a list of paths and/or glob expressions to exclude sources
from the project. The option also accepts a predicate function which is
called for each source path. The exclusion takes place before the file is
read.
"""
@spec read!(t(), input() | [input()], opts()) :: t()
Expand Down Expand Up @@ -258,9 +258,9 @@ defmodule Rewrite do
end

@doc """
Deletes the source for the given `path` from the `rewrite`.
Deletes the source for the given `path` from the `rewrite`.

The file system files are not removed, even if the project is written. Use
The file system files are not removed, even if the project is written. Use
`rm/2` or `rm!/2` to delete a file and source.

If the source is not part of the `rewrite` project the unchanged `rewrite` is
Expand Down Expand Up @@ -293,7 +293,7 @@ defmodule Rewrite do
@doc """
Drops the sources with the given `paths` from the `rewrite` project.

The file system files are not removed, even if the project is written. Use
The file system files are not removed, even if the project is written. Use
`rm/2` or `rm!/2` to delete a file and source.

If `paths` contains paths that are not in `rewrite`, they're simply ignored.
Expand All @@ -315,7 +315,7 @@ defmodule Rewrite do
end

@doc """
Tries to delete the `source` file in the file system and removes the `source`
Tries to delete the `source` file in the file system and removes the `source`
from the `rewrite` project.

Returns `{:ok, rewrite}` if successful, or `{:error, error}` if an error
Expand Down Expand Up @@ -808,7 +808,7 @@ defmodule Rewrite do

Returns `{:ok, rewrite}` if all sources are written successfully.

Returns `{:error, reasons, rewrite}` where `rewrite` is updated for all
Returns `{:error, reasons, rewrite}` where `rewrite` is updated for all
sources that are written successfully.

## Options
Expand Down Expand Up @@ -850,9 +850,9 @@ defmodule Rewrite do
@doc """
Formats the given `rewrite` project with the given `dot_formatter`.

Uses the formatter from `dot_formatter/2` if no formatter ist set by
`:dot_formatter` in the options. The other options are the same as for
`DotFormatter.read!/2`.
Uses the formatter from `dot_formatter/2` if no formatter ist set by
`:dot_formatter` in the options. The other options are the same as for
`DotFormatter.read!/2`.
"""
@spec format(t(), opts()) :: {:ok, t()} | {:error, term()}
def format(%Rewrite{} = rewrite, opts \\ []) do
Expand All @@ -874,9 +874,9 @@ defmodule Rewrite do
@doc """
Formats a source in a `rewrite` project.

Uses the formatter from `dot_formatter/2` if no formatter ist set by
`:dot_formatter` in the options. The other options are the same as for
`Code.format_string!/2`.
Uses the formatter from `dot_formatter/2` if no formatter ist set by
`:dot_formatter` in the options. The other options are the same as for
`Code.format_string!/2`.
"""
@spec format_source(t(), Path.t() | Source.t(), keyword()) :: {:ok, t()} | {:error, term()}
def format_source(rewrite, file, opts \\ [])
Expand Down Expand Up @@ -904,7 +904,7 @@ defmodule Rewrite do
@doc """
Returns the `DotFormatter` for the given `rewrite` project.

When no formatter is set, the default formatter from
When no formatter is set, the default formatter from
`Rewrite.DotFormatter.default/0` is returned. A dot formatter can be set with
`dot_formatter/2`.
"""
Expand All @@ -924,11 +924,11 @@ defmodule Rewrite do
@doc """
Creates a new `%Source{}` and puts the source to the `%Rewrite{}` project.

The `:filetypes` option of the project is used to create the source. If
options have been specified for the file type, the given options will be
The `:filetypes` option of the project is used to create the source. If
options have been specified for the file type, the given options will be
merged into those options.

Use `create_source/4` if the source is not to be inserted directly into the
Use `create_source/4` if the source is not to be inserted directly into the
project.
"""
@spec new_source(t(), Path.t(), String.t(), opts()) :: {:ok, t()} | {:error, Error.t()}
Expand Down Expand Up @@ -958,12 +958,12 @@ defmodule Rewrite do
@doc """
Creates a new `%Source{}` without putting it to the `%Rewrite{}` project.

The `:filetypes` option of the project is used to create the source. If
options have been specified for the file type, the given options will be
merged into those options. If no `path` is given, the default file type is
The `:filetypes` option of the project is used to create the source. If
options have been specified for the file type, the given options will be
merged into those options. If no `path` is given, the default file type is
created.

The function does not check whether the `%Rewrite{}` project already has a
The function does not check whether the `%Rewrite{}` project already has a
`%Source{}` with the specified path.

Use `new_source/4` if the source is to be inserted directly into the project.
Expand Down Expand Up @@ -1023,14 +1023,13 @@ defmodule Rewrite do
end

def slice(rewrite) do
sources = rewrite.sources |> Map.values() |> Enum.sort_by(fn source -> source.path end)
length = length(sources)

{:ok, length,
fn
start, count when start + count == length -> Enum.drop(sources, start)
start, count -> sources |> Enum.drop(start) |> Enum.take(count)
end}
size = map_size(rewrite.sources)

to_list = fn rewrite ->
rewrite.sources |> Map.values() |> Enum.sort_by(fn source -> source.path end)
end

{:ok, size, to_list}
end
Comment thread
NickNeck marked this conversation as resolved.

def reduce(rewrite, acc, fun) do
Expand Down
5 changes: 3 additions & 2 deletions lib/rewrite/dot_formatter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,7 @@ defmodule Rewrite.DotFormatter do
fn input ->
case Code.format_string!(input, formatter_opts) do
[] -> ""
"" -> ""
formatted -> IO.iodata_to_binary([formatted, ?\n])
end
end
Expand Down Expand Up @@ -1175,7 +1176,7 @@ defmodule Rewrite.DotFormatter do
end
end

defp eval_subs(dot_formatter, project, opts) do
defp eval_subs(%DotFormatter{} = dot_formatter, project, opts) do
subdirectories = dot_formatter.subdirectories || []

result =
Expand All @@ -1190,7 +1191,7 @@ defmodule Rewrite.DotFormatter do

case result do
{:error, _reason} = error -> error
result -> {:ok, %DotFormatter{dot_formatter | subs: result}}
result -> {:ok, %{dot_formatter | subs: result}}
end
end

Expand Down
Loading
Loading