tailwindcss-rails 0.2.1 → 0.4.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.
@@ -10,6 +10,10 @@ module Tailwindcss
10
10
  Rails.application.config.assets.precompile += %w( tailwind.css inter-font.css )
11
11
  end
12
12
 
13
+ initializer "tailwindcss.disable_generator_stylesheets" do
14
+ Rails.application.config.generators.stylesheets = false
15
+ end
16
+
13
17
  initializer "tailwindcss.disable_assets_cache" do
14
18
  Rails.application.config.assets.configure do |env|
15
19
  env.cache = ActiveSupport::Cache.lookup_store(:null_store)
@@ -1,8 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Tailwindcss::Purger
2
- CLASS_NAME_PATTERN = /([:A-Za-z0-9_-]+[\.]*[\\\/:A-Za-z0-9_-]*)/
3
- OPENING_SELECTOR_PATTERN = /\..*\{/
4
- CLOSING_SELECTOR_PATTERN = /\s*\}/
5
- NEWLINE = "\n"
4
+ CLASS_NAME_PATTERN = /[:A-Za-z0-9_-]+[\.]*[\\\/:A-Za-z0-9_-]*/
5
+
6
+ CLASS_BREAK = /(?![-_a-z0-9\\])/i # `\b` for class selectors
7
+
8
+ COMMENT = /#{Regexp.escape "/*"}.*?#{Regexp.escape "*/"}/m
9
+ COMMENTS_AND_BLANK_LINES = /\A(?:^#{COMMENT}?[ \t]*(?:\n|\z)|[ \t]*#{COMMENT})+/
10
+
11
+ AT_RULE = /@[^{]+/
12
+ CLASSLESS_SELECTOR_GROUP = /[^.{]+/
13
+ CLASSLESS_BEGINNING_OF_BLOCK = /\A\s*(?:#{AT_RULE}|#{CLASSLESS_SELECTOR_GROUP})\{\n?/
14
+
15
+ SELECTOR_GROUP = /[^{]+/
16
+ BEGINNING_OF_BLOCK = /\A#{SELECTOR_GROUP}\{\n?/
17
+
18
+ PROPERTY_NAME = /[-_a-z0-9]+/i
19
+ PROPERTY_VALUE = /(?:[^;]|;\S)+/
20
+ PROPERTIES = /\A(?:\s*#{PROPERTY_NAME}:#{PROPERTY_VALUE};\n?)+/
21
+
22
+ END_OF_BLOCK = /\A\s*\}\n?/
6
23
 
7
24
  attr_reader :keep_these_class_names
8
25
 
@@ -12,11 +29,15 @@ class Tailwindcss::Purger
12
29
  end
13
30
 
14
31
  def extract_class_names(string)
15
- string.scan(CLASS_NAME_PATTERN).flatten.uniq.sort
32
+ string.scan(CLASS_NAME_PATTERN).uniq.sort!
16
33
  end
17
34
 
18
35
  def extract_class_names_from(files)
19
- Array(files).flat_map { |file| extract_class_names(file.read) }.uniq.sort
36
+ Array(files).flat_map { |file| extract_class_names(file.read) }.uniq.sort!
37
+ end
38
+
39
+ def escape_class_selector(class_name)
40
+ class_name.gsub(/\A\d|[^-_a-z0-9]/, '\\\\\0')
20
41
  end
21
42
  end
22
43
 
@@ -25,40 +46,79 @@ class Tailwindcss::Purger
25
46
  end
26
47
 
27
48
  def purge(input)
28
- inside_kept_selector = inside_ignored_selector = false
29
- output = []
30
-
31
- input.split(NEWLINE).each do |line|
32
- case
33
- when inside_kept_selector
34
- output << line
35
- inside_kept_selector = false if line =~ CLOSING_SELECTOR_PATTERN
36
- when inside_ignored_selector
37
- inside_ignored_selector = false if line =~ CLOSING_SELECTOR_PATTERN
38
- when line =~ OPENING_SELECTOR_PATTERN
39
- if keep_these_class_names.include? class_name_in(line)
40
- output << line
41
- inside_kept_selector = true
42
- else
43
- inside_ignored_selector = true
44
- end
45
- else
46
- output << line
47
- end
49
+ conveyor = Conveyor.new(input)
50
+
51
+ until conveyor.done?
52
+ conveyor.discard(COMMENTS_AND_BLANK_LINES) \
53
+ or conveyor.conditionally_keep(PROPERTIES) { conveyor.staged_output.last != "" } \
54
+ or conveyor.conditionally_keep(END_OF_BLOCK) { not conveyor.staged_output.pop } \
55
+ or conveyor.stage_output(CLASSLESS_BEGINNING_OF_BLOCK) \
56
+ or conveyor.stage_output(BEGINNING_OF_BLOCK) { |match| purge_beginning_of_block(match.to_s) } \
57
+ or raise "infinite loop"
48
58
  end
49
59
 
50
- separated_without_empty_lines(output)
60
+ conveyor.output
51
61
  end
52
62
 
53
63
  private
54
- def class_name_in(line)
55
- CLASS_NAME_PATTERN.match(line)[1]
56
- .remove("\\")
57
- .remove(/:(focus|hover)(-within)?/)
58
- .remove("::placeholder").remove("::-moz-placeholder").remove(":-ms-input-placeholder")
64
+ def keep_these_selectors_pattern
65
+ @keep_these_selectors_pattern ||= begin
66
+ escaped_classes = @keep_these_class_names.map { |name| Regexp.escape self.class.escape_class_selector(name) }
67
+ /(?:\A|,)[^.,{]*(?:[.](?:#{escaped_classes.join("|")})#{CLASS_BREAK}[^.,{]*)*(?=[,{])/
68
+ end
69
+ end
70
+
71
+ def purge_beginning_of_block(string)
72
+ purged = string.scan(keep_these_selectors_pattern).join
73
+ unless purged.empty?
74
+ purged.sub!(/\A,\s*/, "")
75
+ purged.rstrip!
76
+ purged << " {\n"
77
+ end
78
+ purged
59
79
  end
60
80
 
61
- def separated_without_empty_lines(output)
62
- output.reject { |line| line.strip.empty? }.join(NEWLINE)
81
+ class Conveyor
82
+ attr_reader :output, :staged_output
83
+
84
+ def initialize(input, output = +"")
85
+ @input = input
86
+ @output = output
87
+ @staged_output = []
88
+ end
89
+
90
+ def consume(pattern)
91
+ match = pattern.match(@input)
92
+ @input = match.post_match if match
93
+ match
94
+ end
95
+ alias :discard :consume
96
+
97
+ def stage_output(pattern)
98
+ if match = consume(pattern)
99
+ string = block_given? ? (yield match) : match.to_s
100
+ @staged_output << string
101
+ string
102
+ end
103
+ end
104
+
105
+ def keep(pattern)
106
+ if match = consume(pattern)
107
+ string = block_given? ? (yield match) : match.to_s
108
+ @output << @staged_output.shift until @staged_output.empty?
109
+ @output << string
110
+ string
111
+ end
112
+ end
113
+
114
+ def conditionally_keep(pattern)
115
+ keep(pattern) do |match|
116
+ (yield match) ? match.to_s : (break "")
117
+ end
118
+ end
119
+
120
+ def done?
121
+ @input.empty?
122
+ end
63
123
  end
64
124
  end
@@ -1,3 +1,3 @@
1
1
  module Tailwindcss
2
- VERSION = "0.2.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -6,13 +6,20 @@ namespace :tailwindcss do
6
6
 
7
7
  desc "Show the list of class names being kept in Tailwind CSS"
8
8
  task :keeping_class_names do
9
- puts Tailwindcss::Purger.extract_class_names_from(Rails.root.glob("app/views/**/*.*") + Rails.root.glob("app/helpers/**/*.rb"))
9
+ puts Tailwindcss::Purger.extract_class_names_from(default_files_with_class_names)
10
10
  end
11
11
 
12
12
  desc "Show Tailwind CSS styles that are left after purging unused class names"
13
13
  task :preview_purge do
14
- puts Tailwindcss::Purger.purge \
15
- Pathname.new(__FILE__).join("../../../app/assets/stylesheets/tailwind.css").read,
16
- keeping_class_names_from_files: Rails.root.glob("app/views/**/*.*") + Rails.root.glob("app/helpers/**/*.rb")
14
+ puts Tailwindcss::Purger.purge tailwind_css, keeping_class_names_from_files: default_files_with_class_names
17
15
  end
18
16
  end
17
+
18
+ def default_files_with_class_names
19
+ Rails.root.glob("app/views/**/*.*") + Rails.root.glob("app/helpers/**/*.rb")
20
+ end
21
+
22
+ def tailwind_css
23
+ Pathname.new(__FILE__).join("../../../app/assets/stylesheets/tailwind.css").read
24
+ end
25
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tailwindcss-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-18 00:00:00.000000000 Z
11
+ date: 2021-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.0.0
27
- description:
27
+ description:
28
28
  email: david@loudthinking.com
29
29
  executables: []
30
30
  extensions: []
@@ -63,7 +63,7 @@ licenses:
63
63
  - MIT
64
64
  metadata:
65
65
  homepage_uri: https://github.com/rails/tailwindcss-rails
66
- post_install_message:
66
+ post_install_message:
67
67
  rdoc_options: []
68
68
  require_paths:
69
69
  - lib
@@ -78,8 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
78
  - !ruby/object:Gem::Version
79
79
  version: '0'
80
80
  requirements: []
81
- rubygems_version: 3.1.2
82
- signing_key:
81
+ rubygems_version: 3.1.4
82
+ signing_key:
83
83
  specification_version: 4
84
84
  summary: Integrate Tailwind CSS with the asset pipeline in Rails.
85
85
  test_files: []