Module: StimulusPlumbers::Generators::CssEntrypoint

Included in:
InstallGenerator
Defined in:
lib/stimulus_plumbers/generators/css_entrypoint.rb

Constant Summary collapse

STIMULUS_PLUMBERS_CSS_ENTRY =
"STIMULUS_PLUMBERS_CSS_ENTRY"
ENTRY_CANDIDATES =

Shared with stimulus_plumbers_tailwind's InstallGenerator — checked in order, each path is another gem/tool's own default entry file. Detection is theme- agnostic: any of these may be the CSS entry regardless of which theme is active.

[
  "app/assets/stylesheets/application.tailwind.css", # tailwindcss-rails 2.x default
  "app/assets/tailwind/application.css",             # tailwindcss-rails 3.x+ default
  "app/assets/stylesheets/application.css",          # Rails/Propshaft default manifest
  "app/javascript/entrypoints/application.css"       # jsbundling-rails (esbuild/webpack) default
].freeze

Instance Method Summary collapse

Instance Method Details

#append_to_gitignore(path) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 71

def append_to_gitignore(path)
  gitignore = File.join(destination_root, ".gitignore")
  return unless File.exist?(gitignore)

  entry = "/#{relative_to_destination(path)}"
  return if File.readlines(gitignore, chomp: true).include?(entry)
  return if git_ignores?(path)

  File.open(gitignore, "a") { |file| file.puts(entry) }
  say_status :append, ".gitignore", :green
rescue Errno::EROFS, Errno::EACCES => e
  say "Could not update .gitignore: #{e.message}. Skipping.", :yellow
end

#apply_edit(css_file, directive, stale_pattern:, anchor_pattern: nil) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 39

def apply_edit(css_file, directive, stale_pattern:, anchor_pattern: nil)
  content              = File.read(css_file)
  new_content, status  = content_edit(content, directive, stale_pattern: stale_pattern, anchor_pattern: anchor_pattern)

  if new_content
    File.write(css_file, new_content)
    say_status status, relative_to_destination(css_file), :green
  else
    say_status :identical, relative_to_destination(css_file)
  end
rescue Errno::EROFS, Errno::EACCES => e
  say "Could not update #{relative_to_destination(css_file)}: #{e.message}. Skipping.", :yellow
end

#content_edit(content, directive, stale_pattern:, anchor_pattern: nil) ⇒ Object

stale_pattern: is required — every call site needs stale-import detection, so making it optional would leave an untested "anchor without stale" state.



116
117
118
119
120
121
122
123
124
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 116

def content_edit(content, directive, stale_pattern:, anchor_pattern: nil)
  return nil if content.include?(directive)

  if (existing = content.match(stale_pattern))
    return [content.sub(existing[0], directive), :update]
  end

  anchor_pattern ? insert_near_anchor(content, directive, anchor_pattern) : prepend(content, directive)
end

#copy_asset(source, destination) ⇒ Object

CSS copied by an installer belongs to the application from this point on. Keep an existing file intact so a generator rerun never overwrites local customizations (the same policy used by tailwindcss-rails' installer).



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 97

def copy_asset(source, destination)
  path = File.join(destination_root, destination)

  if File.exist?(path)
    say_status :identical, destination
    return true
  end

  FileUtils.mkdir_p(File.dirname(path))
  FileUtils.cp(source, path)
  say_status :create, destination, :green
  true
rescue Errno::EROFS, Errno::EACCES => e
  say "Could not copy #{destination}: #{e.message}. Skipping.", :yellow
  false
end

#entry_css_file(candidates:, env_var:) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 20

def entry_css_file(candidates:, env_var:)
  if ENV[env_var]
    path = File.expand_path(ENV.fetch(env_var, nil))
    return path if File.exist?(path)
  end

  candidates
    .map { |c| File.join(destination_root, c) }
    .find { |f| File.exist?(f) }
end

#git_ignores?(path) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
88
89
90
91
92
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 85

def git_ignores?(path)
  Dir.chdir(destination_root) do
    system("git", "check-ignore", "-q", relative_to_destination(path), out: File::NULL, err: File::NULL)
  end
rescue StandardError => e
  say "Could not check .gitignore coverage with git: #{e.message}. Proceeding to append.", :yellow
  false
end

#insert_near_anchor(content, directive, anchor_pattern) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 130

def insert_near_anchor(content, directive, anchor_pattern)
  if (anchor = content.match(anchor_pattern))
    [content.sub(anchor[0], "#{anchor[0]}\n#{directive}"), :insert]
  else
    ["#{content.rstrip}\n#{directive}\n", :append]
  end
end

#prepend(content, directive) ⇒ Object



126
127
128
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 126

def prepend(content, directive)
  ["#{directive}\n#{content}", :prepend]
end

#relative_to_destination(path) ⇒ Object



138
139
140
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 138

def relative_to_destination(path)
  path.delete_prefix("#{destination_root}/")
end

#remove_lines(css_file, pattern) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 53

def remove_lines(css_file, pattern)
  content = File.read(css_file)
  return unless content.match?(pattern)

  File.write(css_file, content.lines.grep_v(pattern).join)
  say_status :update, relative_to_destination(css_file), :green
rescue Errno::EROFS, Errno::EACCES => e
  say "Could not update #{relative_to_destination(css_file)}: #{e.message}. Skipping.", :yellow
end

#warn_entry_css_not_found(candidates:, env_var:, label:) ⇒ Object



31
32
33
34
35
36
37
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 31

def warn_entry_css_not_found(candidates:, env_var:, label:)
  tried = candidates.map { |c| File.join(destination_root, c) }
  tried.unshift(File.expand_path(ENV[env_var])) if ENV[env_var]
  say "Could not find a #{label} entry file. Tried: #{tried.join(", ")}. " \
      "Set #{env_var}=/path/to/entry.css and re-run.",
      :red
end

#write_generated(path, contents) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/stimulus_plumbers/generators/css_entrypoint.rb', line 63

def write_generated(path, contents)
  FileUtils.mkdir_p(File.dirname(path))
  File.write(path, contents)
  say_status :create, relative_to_destination(path), :green
rescue Errno::EROFS, Errno::EACCES => e
  say "Could not write #{relative_to_destination(path)}: #{e.message}. Skipping.", :yellow
end