diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..84e8759 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +language: elixir + +elixir: + - '1.9' +otp_release: + - '22.0.3' + +matrix: + include: + - elixir: '1.6' + otp_release: '18.3' + - elixir: '1.6' + otp_release: '19.0' + - elixir: '1.6' + otp_release: '20.0' + - elixir: '1.6' + otp_release: '21.0' + - elixir: '1.7' + otp_release: '20.0' + - elixir: '1.7' + otp_release: '21.0' + - elixir: '1.7' + otp_release: '22.0' + - elixir: '1.8' + otp_release: '20.0' + - elixir: '1.8' + otp_release: '21.0' + - elixir: '1.8' + otp_release: '22.0' + - elixir: '1.9' + otp_release: '20.0' + - elixir: '1.9' + otp_release: '21.0' + - elixir: '1.9' + otp_release: '22.0' diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..760b655 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2020 @OldhamMade + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md index 2203cc4..5b20542 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,16 @@ # Sass compiler for Phoenix +[![current build status on Travis-CI.org](https://travis-ci.org/OldhamMade/phoenix_sass.svg?branch=master)][travis] + This library compiles Sass (`.scss` and `.sass`) files to CSS within Phoenix projects. + +## Why? (Rationale) + +One should be able to use Sass with a website without the need for NodeJS. + + ## Installation 1. Add `phoenix_sass` to your list of dependencies in `mix.exs`: @@ -104,9 +112,5 @@ Any Sass file prefixed with an underscore (for example, a file named correctly as an include file (for a file named `app.scss`, for example). -## Why? (Motivation) - -One should be able to use Sass for a website without the need for Webpack. - - +[travis]: https://travis-ci.org/OldhamMade/phoenix_sass [sass_compiler_opts]: https://hexdocs.pm/sass_compiler/Sass.html#module-currently-supported-sass-options diff --git a/lib/mix/tasks/compile.phoenix_sass.ex b/lib/mix/tasks/compile.phoenix_sass.ex index 371f791..59cbfb8 100644 --- a/lib/mix/tasks/compile.phoenix_sass.ex +++ b/lib/mix/tasks/compile.phoenix_sass.ex @@ -48,15 +48,22 @@ defmodule Mix.Tasks.Compile.PhoenixSass do pattern |> Path.wildcard() |> Enum.map(&to_transform/1) + |> Enum.map(&set_basename/1) |> Enum.map(&set_root(&1, root)) |> Enum.map(&set_srcdir(&1, src)) |> Enum.map(&set_destdir(&1, config)) - |> Enum.map(&set_sass_opts(&1, opts)) - |> Enum.map(&do_transform/1) + |> Enum.map(&set_subdir/1) + |> Enum.map(&set_dest(&1)) + |> Enum.map(&set_opts(&1, opts)) + |> Enum.map(&set_sass/1) + |> Enum.map(&write_file/1) end defp to_transform(path), - do: %Transform{ basename: Path.basename(path) } + do: %Transform{ src: path } + + defp set_basename(%Transform{} = transform), + do: %{ transform | basename: Path.basename(transform.src) } defp set_root(%Transform{} = transform, path), do: %{ transform | root: path } @@ -67,16 +74,40 @@ defmodule Mix.Tasks.Compile.PhoenixSass do defp set_destdir(%Transform{} = transform, config), do: %{ transform | destdir: config[:output_dir] } - defp set_sass_opts(%Transform{} = transform, opts), + defp set_subdir(%Transform{} = transform) do + %{ transform | + subdir: transform.src + |> String.replace(transform.root, "") + |> String.replace(transform.srcdir, "") + |> Path.dirname() + } + end + + defp set_dest(%Transform{} = transform), + do: %{ transform | dest: to_path(transform, [:root, :destdir, :subdir, :basename], "css") } + + defp set_opts(%Transform{} = transform, opts), do: %{ transform | opts: opts } - defp do_transform(%Transform{basename: "_" <> _filename} = transform), + defp set_sass(%Transform{basename: "_" <> _filename} = transform), + do: %{ transform | result: :skipped} + defp set_sass(%Transform{} = transform) do + with {:ok, sass} <- Sass.compile_file(transform.src, transform.opts) + do + + %{ transform | sass: sass } + + else + error -> + %{ transform | result: error } + end + end + + defp write_file(%Transform{result: :skipped} = transform), do: %{ transform | result: :skipped} - defp do_transform(%Transform{} = transform) do - with src <- to_path(transform, [:root, :srcdir, :basename]), - dest <- to_path(transform, [:root, :destdir, :basename], "css"), - {:ok, sass} <- Sass.compile_file(src, transform.opts), - :ok <- File.write(dest, sass) + defp write_file(%Transform{} = transform) do + with :ok <- File.mkdir_p(Path.dirname(transform.dest)), + :ok <- File.write(transform.dest, transform.sass) do %{ transform | result: :ok } @@ -101,6 +132,7 @@ defmodule Mix.Tasks.Compile.PhoenixSass do to_path(transform, parts) |> Path.rootname() |> Kernel.<>(".#{ext}") + |> Path.expand() end defp to_path(%Transform{} = transform, parts) do parts @@ -112,8 +144,9 @@ defmodule Mix.Tasks.Compile.PhoenixSass do do: String.contains?(chunk, ["*", "?", "[", "{"]) defp app_dir() do - Mix.Project.config[:app] - |> Application.app_dir() + Mix.Project.config() + # |> Application.app_dir() + |> Mix.Project.app_path() end defp config do diff --git a/lib/transform.ex b/lib/transform.ex index 0883d1e..3c557a9 100644 --- a/lib/transform.ex +++ b/lib/transform.ex @@ -1,10 +1,14 @@ defmodule PhoenixSass.Transform do defstruct [ :root, + :src, :srcdir, + :subdir, :basename, :destdir, + :dest, :opts, + :sass, :result, ] end diff --git a/mix.exs b/mix.exs index c20b806..eb2a21f 100644 --- a/mix.exs +++ b/mix.exs @@ -1,16 +1,16 @@ defmodule PhoenixSass.MixProject do use Mix.Project - @version "0.1.0" + @version "0.1.4" - @description "Compile Sass files to CSS within Phoenix projects" + @description "Auto-compile Sass to CSS within Phoenix projects without NodeJS" @repo_url "https://github.com/OldhamMade/phoenix_sass" def project do [ app: :phoenix_sass, version: @version, - elixir: "~> 1.9", + elixir: "~> 1.6", build_embedded: Mix.env() == :prod, deps: deps(), @@ -20,11 +20,7 @@ defmodule PhoenixSass.MixProject do # Docs name: "phoenix_sass", - docs: [ - source_ref: "v#{@version}", - main: "Phoenix Sass", - source_url: @repo_url - ] + docs: docs() ] end @@ -39,14 +35,22 @@ defmodule PhoenixSass.MixProject do maintainers: ["Phillip Oldham"], licenses: ["Apache 2.0"], links: %{"GitHub" => @repo_url}, - files: ~w(lib mix.exs *.md) + files: ~w(lib .formatter.exs mix.exs *.md LICENSE) ] end defp deps do [ {:sass_compiler, "~> 0.1"}, - {:ex_doc, "~> 0.19", only: :docs} + {:temp, "~> 0.4", only: :test}, + {:ex_doc, ">= 0.0.0", only: :dev, runtime: false} ] end + + defp docs do + [extras: ["README.md"], + main: "readme", + source_ref: "v#{@version}", + source_url: @repo_url] + end end diff --git a/mix.lock b/mix.lock index 822a176..07f1873 100644 --- a/mix.lock +++ b/mix.lock @@ -6,4 +6,5 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"}, "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, "sass_compiler": {:hex, :sass_compiler, "0.1.12", "243a64fdf4ef555e17ef86551539d87dfb2371426134c396e8909845cb062ba0", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "8eee069e1e70d1336b88339fb6150daba7bc2ecfe1ccc44f31aa0af9e51b3a3a"}, + "temp": {:hex, :temp, "0.4.7", "2c78482cc2294020a4bc0c95950b907ff386523367d4e63308a252feffbea9f2", [:mix], [], "hexpm", "6af19e7d6a85a427478be1021574d1ae2a1e1b90882586f06bde76c63cd03e0d"}, } diff --git a/test/fixtures/config/config.exs b/test/fixtures/config/config.exs new file mode 100644 index 0000000..d2d855e --- /dev/null +++ b/test/fixtures/config/config.exs @@ -0,0 +1 @@ +use Mix.Config diff --git a/test/fixtures/priv/sass/_import.sass b/test/fixtures/priv/sass/_import.sass new file mode 100644 index 0000000..54c2210 --- /dev/null +++ b/test/fixtures/priv/sass/_import.sass @@ -0,0 +1,2 @@ +body + background: green diff --git a/test/fixtures/priv/sass/main.sass b/test/fixtures/priv/sass/main.sass new file mode 100644 index 0000000..ace028e --- /dev/null +++ b/test/fixtures/priv/sass/main.sass @@ -0,0 +1 @@ +@import _import.sass diff --git a/test/fixtures/priv/sass/sub/extra.sass b/test/fixtures/priv/sass/sub/extra.sass new file mode 100644 index 0000000..4a8b14d --- /dev/null +++ b/test/fixtures/priv/sass/sub/extra.sass @@ -0,0 +1,2 @@ +body + background: blue diff --git a/test/mix/tasks/compile.phoenix_sass_test.exs b/test/mix/tasks/compile.phoenix_sass_test.exs new file mode 100644 index 0000000..a10faeb --- /dev/null +++ b/test/mix/tasks/compile.phoenix_sass_test.exs @@ -0,0 +1,67 @@ +defmodule Mix.Tasks.Compile.PhoenixSassTest do + use ExUnit.Case + + @fixtures_path "../../fixtures" |> Path.expand(__DIR__) + + defmodule TestProject do + def project do + [ + app: :test_project + ] + end + end + + setup do + # Temp.track! + {:ok, test_dir} = Temp.mkdir "_build" + + System.put_env("MIX_BUILD_PATH", test_dir) + + Mix.Project.push( + TestProject + ) + + File.mkdir_p!(app_dir()) + File.cp_r!(@fixtures_path, app_dir()) + + on_exit(&Mix.Project.pop/0) + + :ok + end + + test "setup completed successfully" do + assert File.exists?(Path.join([app_dir(), "config", "config.exs"])) + end + + describe "PhoenixSass" do + test "compiles sass to css successfully" do + Mix.Tasks.Compile.PhoenixSass.run([]) + + assert File.exists?(Path.join([app_dir(), "priv", "static", "css", "main.css"])) + end + + test "compiles sass in subdirs to css successfully" do + Mix.Tasks.Compile.PhoenixSass.run([]) + + assert File.exists?(Path.join([app_dir(), "priv", "static", "css", "sub", "extra.css"])) + end + + test "skips sass with underscore prefix successfully" do + Mix.Tasks.Compile.PhoenixSass.run([]) + + assert File.exists?(Path.join([app_dir(), "priv", "sass", "_import.sass"])) + assert !File.exists?(Path.join([app_dir(), "priv", "static", "css", "_import.css"])) + + assert 2 == ( + Path.join([app_dir(), "priv", "static", "css", "**", "*.css"]) + |> Path.wildcard() + |> Enum.count() + ) + end + end + + defp app_dir() do + Mix.Project.config() + |> Mix.Project.app_path() + end +end diff --git a/test/phoenix_sass_test.exs b/test/phoenix_sass_test.exs new file mode 100644 index 0000000..ce66cb9 --- /dev/null +++ b/test/phoenix_sass_test.exs @@ -0,0 +1,8 @@ +defmodule PhoenixSassTest do + use ExUnit.Case + # doctest PhoenixSass + + # test "greets the world" do + # assert PhoenixSass.hello() == :world + # end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()