tailwind-sorter 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +31 -8
- data/exe/tailwind_sorter +8 -5
- data/lib/tailwind_sorter/config.rb +35 -0
- data/lib/tailwind_sorter/dsl.rb +17 -0
- data/lib/tailwind_sorter/file_sorter.rb +87 -0
- data/lib/tailwind_sorter/sortable.rb +59 -0
- data/lib/tailwind_sorter/string_sorter.rb +21 -0
- data/lib/tailwind_sorter/version.rb +3 -1
- data/lib/tailwind_sorter.rb +5 -1
- metadata +7 -3
- data/lib/tailwind_sorter/sorter.rb +0 -148
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5b16162e06cb7a443fe14cb3789db5c9acc19ee0f142d6033645e52b3e54ac5
|
4
|
+
data.tar.gz: 2f8f31eebb9b06407e38dc0e955324c543a2f7a3bd5f0826474055322f1710d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ee3992e5ef6237c10a56d44955a84f4791bbdc021238c72de8cc8a4054076486a0da17eb6626f742a59922baf83758000a5dc3cf248984da568c6113acd60f3
|
7
|
+
data.tar.gz: 13ac69950d1fe543a14bf32752caa323a38fa23704c6e311517307bf506d17f8e55cea0226bca03b17796911737d031dfd8fe450c2414c8ce866493b665216cd
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
### 0.5.0
|
2
|
+
|
3
|
+
Restructure the gem completely:
|
4
|
+
|
5
|
+
- extract `FileSorter` (that can sort classes in a file) and a new `StringSorter` (that can sort classes in a string)
|
6
|
+
- clean up the code into their own modules / classes
|
7
|
+
- add a DSL for running the sorters from ruby code
|
8
|
+
- enhance the tests
|
9
|
+
|
10
|
+
**BREAKING CHANGE**: if you called the file sorter from ruby like this:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
TailwindSorter::Sorter.run(file_name, warn_only: true/false, config_file: "some_config")
|
14
|
+
```
|
15
|
+
|
16
|
+
you need to change the call to the new syntax:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
TailwindSorter.sort_file(file_name, warn_only: true/false, config_file: "some_config")
|
20
|
+
|
21
|
+
```
|
22
|
+
|
23
|
+
### 0.4.1
|
24
|
+
|
25
|
+
Add support for processing multiple files at once.
|
26
|
+
|
1
27
|
### 0.4.0
|
2
28
|
|
3
29
|
- Add support for regular expressions in configuration for class ordering (#3)
|
data/README.md
CHANGED
@@ -2,12 +2,11 @@
|
|
2
2
|
|
3
3
|
**A ruby gem to sort the [Tailwind CSS](https://tailwindcss.com) classes in your templates _the custom way_.**
|
4
4
|
|
5
|
-
The gem contains a standalone executable script that can work in two ways:
|
5
|
+
The gem contains a sorting library and a standalone executable script that can work in two ways:
|
6
6
|
|
7
7
|
- it can edit the given file in place (especially useful when hooked up to a file changes watcher) or
|
8
8
|
- it can just generate warning messages suitable for [Overcommit](https://github.com/sds/overcommit),
|
9
|
-
[Lefthook](https://github.com/evilmartians/lefthook) or any other similar system
|
10
|
-
prefer).
|
9
|
+
[Lefthook](https://github.com/evilmartians/lefthook) or any other similar system.
|
11
10
|
|
12
11
|
Out of the box the script supports sorting classes in [Slim templates](http://slim-lang.com/) but can be configured for
|
13
12
|
anything else. The script also removes duplicate classes.
|
@@ -163,6 +162,12 @@ The script requires the configuration file to be present in `config/tailwind_sor
|
|
163
162
|
bin/tailwind_sorter -c path/to/my/config_file.yml app/views/my_template.html.slim
|
164
163
|
```
|
165
164
|
|
165
|
+
Multiple files can be processed in a single run:
|
166
|
+
|
167
|
+
```sh
|
168
|
+
bin/tailwind_sorter app/views/my_template.html.slim app/views/another_template.html.slim
|
169
|
+
```
|
170
|
+
|
166
171
|
## Running automatically via your IDE / editor
|
167
172
|
|
168
173
|
Perhaps the best way to run the script is using your editor or IDE. Many editors provide the possibility to watch your
|
@@ -186,20 +191,36 @@ problems found.
|
|
186
191
|
To run the sorter from ruby code, use the following line:
|
187
192
|
|
188
193
|
```ruby
|
189
|
-
TailwindSorter
|
194
|
+
TailwindSorter.sort_file("app/views/my_template.html.slim")
|
195
|
+
```
|
196
|
+
|
197
|
+
You can also optionally pass in some arguments such as `warn_only: true` to only show warning instead of overwriting the file or `config_file: "path/to/my/config_file.yml"` for custom config path.
|
198
|
+
|
199
|
+
## Sorting Tailwind classes from ruby code
|
200
|
+
|
201
|
+
You can also use this gem as a library and sort a single string with Tailwind classes:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
>> TailwindSorter.sort("my-4 block absolute")
|
205
|
+
=> "absolute block my-4"
|
206
|
+
```
|
207
|
+
|
208
|
+
Optionally also with a custom config file:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
TailwindSorter.sort("my-4 block absolute", config_file: "path/to/my/config_file.yml")
|
190
212
|
```
|
191
213
|
|
192
|
-
You can also optionally pass in ome arguments such as `warn_only: true` to only show warning instead of overwriting the file or `config_file: "path/to/my/config_file.yml"` for custom config path.
|
193
214
|
|
194
215
|
## Running tests
|
195
216
|
|
196
217
|
```sh
|
197
218
|
bundle install # to install the rspec gem
|
198
219
|
bundle exec rspec
|
199
|
-
|
220
|
+
..................................
|
200
221
|
|
201
|
-
Finished in
|
202
|
-
|
222
|
+
Finished in 0.28774 seconds (files took 0.06508 seconds to load)
|
223
|
+
34 examples, 0 failures
|
203
224
|
```
|
204
225
|
|
205
226
|
## Answers for the curious
|
@@ -209,3 +230,5 @@ Finished in 1.08 seconds (files took 0.03424 seconds to load)
|
|
209
230
|
When we initially reordered CSS classes in all our templates (~900 Slim files) with the script changing nearly 4000
|
210
231
|
lines, the whole process took less than 30 seconds. This makes the processing speed of approximately 30 files per
|
211
232
|
second. Judge for yourself if this is fast enough for your needs or not.
|
233
|
+
|
234
|
+
**Update**: this is a benchmark of an old version of the gem which supported sorting only a single file at once. Since version 0.4.1 the script can process multiple files in a single run and as this skips repeated loading of ruby it speeds up the bulk sorting process in an order of magnitude.
|
data/exe/tailwind_sorter
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
lib = File.expand_path(File.dirname(__FILE__)
|
3
|
+
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
|
4
4
|
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
5
|
|
6
6
|
require "tailwind_sorter"
|
7
7
|
|
8
8
|
warn_only = false
|
9
|
-
config_file =
|
9
|
+
config_file = TailwindSorter::Config::DEFAULT_CONFIG_FILE
|
10
10
|
|
11
11
|
while (arg = ARGV.shift)
|
12
12
|
case arg
|
@@ -15,13 +15,16 @@ while (arg = ARGV.shift)
|
|
15
15
|
when "-c"
|
16
16
|
config_file = ARGV.shift
|
17
17
|
else
|
18
|
-
|
18
|
+
ARGV.unshift(arg)
|
19
|
+
break
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
23
|
begin
|
23
|
-
|
24
|
+
while (file_name = ARGV.shift)
|
25
|
+
TailwindSorter.sort_file(file_name, warn_only:, config_file:)
|
26
|
+
end
|
24
27
|
rescue ArgumentError => e
|
25
|
-
|
28
|
+
warn e.message
|
26
29
|
exit 1
|
27
30
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TailwindSorter
|
4
|
+
class Config
|
5
|
+
DEFAULT_CONFIG_FILE = "config/tailwind_sorter.yml"
|
6
|
+
|
7
|
+
def initialize(config_file = DEFAULT_CONFIG_FILE)
|
8
|
+
unless config_file && File.exist?(config_file)
|
9
|
+
raise ArgumentError, "Configuration file '#{config_file}' does not exist"
|
10
|
+
end
|
11
|
+
|
12
|
+
@config_file = config_file
|
13
|
+
end
|
14
|
+
|
15
|
+
def load
|
16
|
+
@config = YAML.load_file(@config_file)
|
17
|
+
convert_class_order_regexps!
|
18
|
+
@config
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def convert_class_order_regexps!
|
24
|
+
@config["classes_order"].each_value do |class_patterns|
|
25
|
+
class_patterns.map! do |class_or_pattern|
|
26
|
+
if (patterns = class_or_pattern.match(%r{\A/(.*)/\z}).to_a).empty?
|
27
|
+
class_or_pattern
|
28
|
+
else
|
29
|
+
/\A#{patterns.last}\z/
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tailwind_sorter/config"
|
4
|
+
require "tailwind_sorter/string_sorter"
|
5
|
+
require "tailwind_sorter/file_sorter"
|
6
|
+
|
7
|
+
module TailwindSorter
|
8
|
+
module DSL
|
9
|
+
def sort(classes_string, config_file: Config::DEFAULT_CONFIG_FILE)
|
10
|
+
TailwindSorter::StringSorter.new(config_file:).sort(classes_string)
|
11
|
+
end
|
12
|
+
|
13
|
+
def sort_file(file, warn_only: false, config_file: Config::DEFAULT_CONFIG_FILE)
|
14
|
+
TailwindSorter::FileSorter.new(warn_only:, config_file:).sort(file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tempfile"
|
4
|
+
require "yaml"
|
5
|
+
|
6
|
+
require "tailwind_sorter/config"
|
7
|
+
require "tailwind_sorter/sortable"
|
8
|
+
|
9
|
+
module TailwindSorter
|
10
|
+
class FileSorter
|
11
|
+
include Sortable
|
12
|
+
|
13
|
+
def initialize(warn_only: false, config_file: Config::DEFAULT_CONFIG_FILE)
|
14
|
+
@warn_only = warn_only
|
15
|
+
@config = Config.new(config_file).load
|
16
|
+
|
17
|
+
@sorting_keys_cache = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def sort(file_name)
|
21
|
+
raise ArgumentError, "File '#{file_name}' does not exist" unless file_name && File.exist?(file_name)
|
22
|
+
|
23
|
+
sort_classes(file_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def sort_classes(file)
|
29
|
+
warnings = []
|
30
|
+
|
31
|
+
infile = File.open(file)
|
32
|
+
outfile = Tempfile.create("#{File.basename(file)}.sorted")
|
33
|
+
changed = false
|
34
|
+
|
35
|
+
infile.each_line do |line|
|
36
|
+
line_number = infile.lineno
|
37
|
+
|
38
|
+
line_regexps_for(file).each_value do |regexp_config|
|
39
|
+
regexp = regexp_config["regexp"]
|
40
|
+
prefix = regexp_config["class_prefix"]
|
41
|
+
split_by = "#{regexp_config['class_splitter']}#{prefix}"
|
42
|
+
|
43
|
+
next unless (match = line.match(regexp))
|
44
|
+
|
45
|
+
classes = match["classes"]
|
46
|
+
classes = classes.split(split_by).map(&:strip).reject(&:empty?).uniq
|
47
|
+
sorted_classes = sort_classes_array(classes)
|
48
|
+
|
49
|
+
if @warn_only
|
50
|
+
orig_keys = classes.map { |css_class| sorting_key_lambda.call(css_class) }
|
51
|
+
sorted_keys = sorted_classes.map { |css_class| sorting_key_lambda.call(css_class) }
|
52
|
+
|
53
|
+
if orig_keys != sorted_keys
|
54
|
+
warning = "#{file}:#{line_number}:CSS classes are not sorted well. Please run 'tailwind_sorter #{file}'."
|
55
|
+
warnings << warning
|
56
|
+
puts(warning)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
orig_line = line.dup unless changed
|
60
|
+
line.sub!(regexp, "\\k<before>#{prefix}#{sorted_classes.join(split_by)}")
|
61
|
+
changed = true if !changed && line != orig_line
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
outfile.puts line
|
66
|
+
end
|
67
|
+
|
68
|
+
success = true
|
69
|
+
|
70
|
+
warnings
|
71
|
+
rescue StandardError => e
|
72
|
+
warn "An error occurred: #{e}"
|
73
|
+
success = false
|
74
|
+
ensure
|
75
|
+
infile.close
|
76
|
+
outfile.close
|
77
|
+
|
78
|
+
success && changed ? FileUtils.mv(outfile, file) : File.unlink(outfile)
|
79
|
+
end
|
80
|
+
|
81
|
+
def line_regexps_for(file)
|
82
|
+
line_regexps = @config["regexps"].select { |_k, v| v["file_extension"] == File.extname(file) }
|
83
|
+
line_regexps.each_value { |v| v["regexp"] = Regexp.new(v["regexp"]) }
|
84
|
+
line_regexps
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TailwindSorter
|
4
|
+
module Sortable
|
5
|
+
private
|
6
|
+
|
7
|
+
# Returns the Tailwind classes array sorted according to the config file.
|
8
|
+
def sort_classes_array(classes)
|
9
|
+
classes = classes.map do |css_class_with_variants|
|
10
|
+
sort_variants(css_class_with_variants)
|
11
|
+
end
|
12
|
+
|
13
|
+
classes.sort_by { |css_class| sorting_key_lambda.call(css_class) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Lambda for sorting the Tailwind CSS classes. It is memoized to avoid repeated class groups lookups.
|
17
|
+
def sorting_key_lambda(default_index: 0)
|
18
|
+
@sorting_key_lambda ||= begin
|
19
|
+
class_groups = @config["classes_order"].keys
|
20
|
+
->(tw_class) { sorting_key(tw_class, class_groups:, default_index:) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Reorders multiple variants, e.g.: "focus:sm:block" -> "sm:focus:block".
|
25
|
+
def sort_variants(css_class_with_variants)
|
26
|
+
*variants, css_class = css_class_with_variants.split(":")
|
27
|
+
return css_class_with_variants if variants.length <= 1
|
28
|
+
|
29
|
+
variants.sort_by! { |variant| @config["variants_order"].index(variant) }
|
30
|
+
"#{variants.join(':')}:#{css_class}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Constructs the sorting key for sorting CSS classes in the following way:
|
34
|
+
#
|
35
|
+
# group_index, variant1_index, variant2_index, class_index
|
36
|
+
# "sm:focus:flex" -> "01,01,11,0010"
|
37
|
+
# "flex" -> "01,00,00,0010"
|
38
|
+
# "custom-class" -> "00,00,00,0000"
|
39
|
+
def sorting_key(css_class_with_variants, class_groups:, default_index: 0)
|
40
|
+
return @sorting_keys_cache[css_class_with_variants] if @sorting_keys_cache[css_class_with_variants]
|
41
|
+
|
42
|
+
*variants, css_class = css_class_with_variants.split(":")
|
43
|
+
|
44
|
+
matching_index_in_group = nil
|
45
|
+
matching_group = class_groups.find do |group|
|
46
|
+
matching_index_in_group ||= @config["classes_order"][group].index { _1 === css_class }
|
47
|
+
end
|
48
|
+
|
49
|
+
key = [
|
50
|
+
format("%02d", (matching_group && class_groups.index(matching_group)) || default_index),
|
51
|
+
format("%02d", @config["variants_order"].index(variants[0]) || default_index),
|
52
|
+
format("%02d", @config["variants_order"].index(variants[1]) || default_index),
|
53
|
+
format("%04d", matching_index_in_group || default_index)
|
54
|
+
].join(",")
|
55
|
+
|
56
|
+
@sorting_keys_cache[css_class_with_variants] = key
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
require "tailwind_sorter/config"
|
6
|
+
require "tailwind_sorter/sortable"
|
7
|
+
|
8
|
+
module TailwindSorter
|
9
|
+
class StringSorter
|
10
|
+
include Sortable
|
11
|
+
|
12
|
+
def initialize(config_file: Config::DEFAULT_CONFIG_FILE)
|
13
|
+
@config = Config.new(config_file).load
|
14
|
+
@sorting_keys_cache = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def sort(classes_string)
|
18
|
+
sort_classes_array(classes_string.split.map(&:strip).reject(&:empty?).uniq).join(" ")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/tailwind_sorter.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tailwind-sorter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NejŘemeslníci.cz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Simple but customizable sorter for TailwindCSS classes
|
14
14
|
email:
|
@@ -23,7 +23,11 @@ files:
|
|
23
23
|
- Rakefile
|
24
24
|
- exe/tailwind_sorter
|
25
25
|
- lib/tailwind_sorter.rb
|
26
|
-
- lib/tailwind_sorter/
|
26
|
+
- lib/tailwind_sorter/config.rb
|
27
|
+
- lib/tailwind_sorter/dsl.rb
|
28
|
+
- lib/tailwind_sorter/file_sorter.rb
|
29
|
+
- lib/tailwind_sorter/sortable.rb
|
30
|
+
- lib/tailwind_sorter/string_sorter.rb
|
27
31
|
- lib/tailwind_sorter/version.rb
|
28
32
|
homepage: https://github.com/NejRemeslnici/tailwind-sorter
|
29
33
|
licenses:
|
@@ -1,148 +0,0 @@
|
|
1
|
-
require "tempfile"
|
2
|
-
require "yaml"
|
3
|
-
|
4
|
-
module TailwindSorter
|
5
|
-
class Sorter
|
6
|
-
def initialize
|
7
|
-
@sorting_keys_cache = {}
|
8
|
-
end
|
9
|
-
|
10
|
-
# reorders multiple variants, e.g.: "focus:sm:block" -> "sm:focus:block"
|
11
|
-
def sort_variants(css_class_with_variants, variants_order:)
|
12
|
-
*variants, css_class = css_class_with_variants.split(":")
|
13
|
-
return css_class_with_variants if variants.length <= 1
|
14
|
-
|
15
|
-
variants.sort_by! { |variant| variants_order.index(variant) }
|
16
|
-
"#{variants.join(':')}:#{css_class}"
|
17
|
-
end
|
18
|
-
|
19
|
-
# Constructs the sorting key for sorting CSS classes in the following way:
|
20
|
-
#
|
21
|
-
# group_index, variant1_index, variant2_index, class_index
|
22
|
-
# "sm:focus:flex" -> "01,01,11,0010"
|
23
|
-
# "flex" -> "01,00,00,0010"
|
24
|
-
# "custom-class" -> "00,00,00,0000"
|
25
|
-
def sorting_key(css_class_with_variants, variants_order:, classes_order:, class_groups:, default_index: 0)
|
26
|
-
return @sorting_keys_cache[css_class_with_variants] if @sorting_keys_cache[css_class_with_variants]
|
27
|
-
|
28
|
-
*variants, css_class = css_class_with_variants.split(":")
|
29
|
-
|
30
|
-
matching_index_in_group = nil
|
31
|
-
matching_group = class_groups.find do |group|
|
32
|
-
matching_index_in_group ||= classes_order[group].index { _1 === css_class }
|
33
|
-
end
|
34
|
-
|
35
|
-
key = [
|
36
|
-
format("%02d", matching_group && class_groups.index(matching_group) || default_index),
|
37
|
-
format("%02d", variants_order.index(variants[0]) || default_index),
|
38
|
-
format("%02d", variants_order.index(variants[1]) || default_index),
|
39
|
-
format("%04d", matching_index_in_group || default_index)
|
40
|
-
].join(",")
|
41
|
-
|
42
|
-
# puts "#{css_class_with_variants} #{key}"
|
43
|
-
@sorting_keys_cache[css_class_with_variants] = key
|
44
|
-
end
|
45
|
-
|
46
|
-
def convert_regexps!(classes_order)
|
47
|
-
classes_order.each do |group, class_patterns|
|
48
|
-
class_patterns.map! do |class_or_pattern|
|
49
|
-
if !(patterns = class_or_pattern.match(%r{\A/(.*)/\z}).to_a).empty?
|
50
|
-
Regexp.new(/\A#{patterns.last}\z/)
|
51
|
-
else
|
52
|
-
class_or_pattern
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
classes_order
|
58
|
-
end
|
59
|
-
|
60
|
-
def sort_classes(file, regexps:, variants_order:, classes_order:, default_index: 0, warn_only: false)
|
61
|
-
convert_regexps!(classes_order)
|
62
|
-
class_groups = classes_order.keys
|
63
|
-
warnings = []
|
64
|
-
|
65
|
-
infile = File.open(file)
|
66
|
-
outfile = Tempfile.create("#{File.basename(file)}.sorted")
|
67
|
-
|
68
|
-
calculate_sorting_key = lambda do |css_class_with_variants|
|
69
|
-
sorting_key(css_class_with_variants, variants_order:, classes_order:, class_groups:, default_index:)
|
70
|
-
end
|
71
|
-
|
72
|
-
changed = false
|
73
|
-
infile.each_line do |line|
|
74
|
-
line_number = infile.lineno
|
75
|
-
|
76
|
-
regexps.each do |_regexp_name, regexp_config|
|
77
|
-
regexp = regexp_config["regexp"]
|
78
|
-
prefix = regexp_config["class_prefix"]
|
79
|
-
split_by = "#{regexp_config['class_splitter']}#{prefix}"
|
80
|
-
|
81
|
-
next unless (match = line.match(regexp))
|
82
|
-
|
83
|
-
matched_classes = match["classes"]
|
84
|
-
# puts "#{line_number}: #{matched_classes}"
|
85
|
-
|
86
|
-
classes = matched_classes.split(split_by).map(&:strip).reject(&:empty?).uniq.map do |css_class_with_variants|
|
87
|
-
sort_variants(css_class_with_variants, variants_order: variants_order)
|
88
|
-
end
|
89
|
-
|
90
|
-
sorted_classes = classes.sort_by { |css_class| calculate_sorting_key.call(css_class) }
|
91
|
-
# puts sorted_classes.join('.')
|
92
|
-
|
93
|
-
if warn_only
|
94
|
-
orig_keys = classes.map { |css_class| calculate_sorting_key.call(css_class) }
|
95
|
-
sorted_keys = sorted_classes.map { |css_class| calculate_sorting_key.call(css_class) }
|
96
|
-
# puts orig_keys.inspect
|
97
|
-
# puts sorted_keys.inspect
|
98
|
-
if orig_keys != sorted_keys
|
99
|
-
warning = "#{file}:#{line_number}:CSS classes are not sorted well. Please run 'tailwind_sorter #{file}'."
|
100
|
-
warnings << warning
|
101
|
-
puts(warning)
|
102
|
-
end
|
103
|
-
else
|
104
|
-
orig_line = line.dup unless changed
|
105
|
-
line.sub!(regexp, "\\k<before>#{prefix}#{sorted_classes.join(split_by)}")
|
106
|
-
changed = true if !changed && line != orig_line
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
outfile.puts line
|
111
|
-
end
|
112
|
-
|
113
|
-
success = true
|
114
|
-
|
115
|
-
warnings
|
116
|
-
|
117
|
-
rescue StandardError => e
|
118
|
-
warn "An error occurred: #{e}"
|
119
|
-
success = false
|
120
|
-
|
121
|
-
ensure
|
122
|
-
infile.close
|
123
|
-
outfile.close
|
124
|
-
|
125
|
-
success && changed ? FileUtils.mv(outfile, file) : File.unlink(outfile)
|
126
|
-
end
|
127
|
-
|
128
|
-
def run(file_name, warn_only: false, config_file: "config/tailwind_sorter.yml")
|
129
|
-
raise ArgumentError, "File '#{file_name}' does not exist" unless file_name && File.exist?(file_name)
|
130
|
-
raise ArgumentError, "Configuration file '#{config_file}' does not exist" unless config_file && File.exist?(config_file)
|
131
|
-
|
132
|
-
config = YAML.load_file(config_file)
|
133
|
-
file_extension = File.extname(file_name)
|
134
|
-
|
135
|
-
regexps = config["regexps"].select { |_k, v| v["file_extension"] == file_extension }
|
136
|
-
regexps.each { |_k, v| v["regexp"] = Regexp.new(v["regexp"]) }
|
137
|
-
|
138
|
-
sort_classes(file_name, regexps:,
|
139
|
-
classes_order: config["classes_order"],
|
140
|
-
variants_order: config["variants_order"],
|
141
|
-
warn_only:)
|
142
|
-
end
|
143
|
-
|
144
|
-
def self.run(...)
|
145
|
-
new.run(...)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|