tailwind-sorter 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|