@@ -12,6 +12,66 @@ defmodule TailwindCompiler do
1212
1313 """
1414
15+ @ doc """
16+ Extract Tailwind candidate strings from source text.
17+
18+ This accepts raw HTML, templates, JavaScript/Elixir/Lua string literals, or
19+ any other source-like text. It intentionally over-collects candidate-like
20+ tokens; use `validate/1` or `compile/2` to let the compiler decide which
21+ tokens are real utilities.
22+
23+ When passed a binary or iodata, this returns a list. When passed an enumerable
24+ such as `IO.stream/2` or `File.stream!/3`, this returns a lazy stream of
25+ unique candidate strings.
26+
27+ ## Examples
28+
29+ TailwindCompiler.candidates(~s(<div class="flex p-4"></div>))
30+ #=> ["div", "flex", "p-4", "/div"]
31+
32+ File.stream!("index.html", [], :line)
33+ |> TailwindCompiler.candidates()
34+ |> Enum.to_list()
35+
36+ """
37+ @ spec candidates ( iodata ( ) ) :: [ String . t ( ) ]
38+ @ spec candidates ( Enumerable . t ( ) ) :: Enumerable . t ( )
39+ def candidates ( source ) when is_binary ( source ) or is_list ( source ) do
40+ TailwindCompiler.Candidates . extract ( source )
41+ end
42+
43+ def candidates ( source ) do
44+ if Enumerable . impl_for ( source ) do
45+ TailwindCompiler.Candidates . stream ( source )
46+ else
47+ raise ArgumentError , "expected source to be iodata or an enumerable of iodata chunks"
48+ end
49+ end
50+
51+ @ doc """
52+ Extract candidates from source text and compile them into CSS.
53+
54+ This is a convenience wrapper around `candidates/1` and `compile/2`.
55+ """
56+ @ spec compile_source ( iodata ( ) | Enumerable . t ( ) , keyword ( ) ) ::
57+ { :ok , String . t ( ) } | { :error , term ( ) }
58+ def compile_source ( source , opts \\ [ ] ) do
59+ source
60+ |> candidates ( )
61+ |> compile ( opts )
62+ end
63+
64+ @ doc """
65+ Same as `compile_source/2` but raises on error.
66+ """
67+ @ spec compile_source! ( iodata ( ) | Enumerable . t ( ) , keyword ( ) ) :: String . t ( )
68+ def compile_source! ( source , opts \\ [ ] ) do
69+ case compile_source ( source , opts ) do
70+ { :ok , css } -> css
71+ { :error , reason } -> raise "TailwindCompiler.compile_source!/2 failed: #{ inspect ( reason ) } "
72+ end
73+ end
74+
1575 @ doc """
1676 Compile a list of Tailwind CSS candidate strings into minified CSS.
1777
@@ -50,8 +110,11 @@ defmodule TailwindCompiler do
50110 #=> {:ok, "...bg-primary{background-color:var(--color-primary)}..."}
51111
52112 """
53- @ spec compile ( [ String . t ( ) ] , keyword ( ) ) :: { :ok , String . t ( ) } | { :error , term ( ) }
54- def compile ( candidates , opts \\ [ ] ) when is_list ( candidates ) do
113+ @ spec compile ( [ String . t ( ) ] | Enumerable . t ( ) , keyword ( ) ) ::
114+ { :ok , String . t ( ) } | { :error , term ( ) }
115+ def compile ( candidates , opts \\ [ ] )
116+
117+ def compile ( candidates , opts ) when is_list ( candidates ) do
55118 theme_json = Keyword . get ( opts , :theme )
56119 preflight = Keyword . get ( opts , :preflight , true )
57120 minify = Keyword . get ( opts , :minify , true )
@@ -66,14 +129,32 @@ defmodule TailwindCompiler do
66129 str when is_binary ( str ) -> str
67130 end
68131
69- case TailwindCompiler.NIF . compile ( candidates , theme_json || "" , preflight , minify , custom_css || "" , custom_utilities_json , plugin_css || "" ) do
132+ case TailwindCompiler.NIF . compile (
133+ candidates ,
134+ theme_json || "" ,
135+ preflight ,
136+ minify ,
137+ custom_css || "" ,
138+ custom_utilities_json ,
139+ plugin_css || ""
140+ ) do
70141 result when is_binary ( result ) -> { :ok , result }
71142 error -> { :error , error }
72143 end
73144 rescue
74145 e -> { :error , Exception . message ( e ) }
75146 end
76147
148+ def compile ( candidates , opts ) do
149+ if Enumerable . impl_for ( candidates ) do
150+ candidates
151+ |> Enum . to_list ( )
152+ |> compile ( opts )
153+ else
154+ { :error , "expected candidates to be a list or enumerable of strings" }
155+ end
156+ end
157+
77158 @ doc """
78159 Same as `compile/2` but raises on error.
79160 """
0 commit comments