mint 0.8.0 → 0.10.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -26
  3. data/README.md +138 -95
  4. data/bin/mint +2 -81
  5. data/config/templates/base/navigation.css +136 -0
  6. data/config/templates/base/print.css +152 -0
  7. data/config/templates/{reset.css → base/reset.css} +1 -1
  8. data/config/templates/base/style.css +117 -137
  9. data/config/templates/base/utilities.css +136 -0
  10. data/config/templates/base/variables.css +124 -0
  11. data/config/templates/basic/style.css +151 -0
  12. data/config/templates/default/layout.erb +33 -3
  13. data/config/templates/default/style.css +95 -164
  14. data/config/templates/magazine/style.css +383 -0
  15. data/config/templates/nord/style.css +105 -220
  16. data/config/templates/nord-dark/style.css +82 -263
  17. data/lib/mint/commandline/parse.rb +144 -0
  18. data/lib/mint/commandline/publish.rb +46 -0
  19. data/lib/mint/commandline/run.rb +30 -0
  20. data/lib/mint/config.rb +162 -0
  21. data/lib/mint/{css.rb → css_dsl.rb} +9 -9
  22. data/lib/mint/css_parser.rb +96 -0
  23. data/lib/mint/document.rb +251 -348
  24. data/lib/mint/document_tree.rb +163 -0
  25. data/lib/mint/exceptions.rb +2 -3
  26. data/lib/mint/helpers.rb +23 -180
  27. data/lib/mint/layout.rb +26 -9
  28. data/lib/mint/renderers/css_renderer.rb +32 -0
  29. data/lib/mint/renderers/erb_renderer.rb +11 -0
  30. data/lib/mint/renderers/markdown_renderer.rb +45 -0
  31. data/lib/mint/style.rb +21 -31
  32. data/lib/mint/template.rb +30 -0
  33. data/lib/mint/version.rb +1 -1
  34. data/lib/mint/workspace.rb +171 -0
  35. data/lib/mint.rb +44 -12
  36. data/man/mint.1 +88 -47
  37. data/spec/cli/README.md +13 -13
  38. data/spec/cli/argument_parsing_spec.rb +103 -131
  39. data/spec/cli/bin_integration_spec.rb +23 -243
  40. data/spec/cli/full_workflow_integration_spec.rb +99 -442
  41. data/spec/cli/original_style_integration_spec.rb +58 -0
  42. data/spec/cli/publish_workflow_spec.rb +72 -70
  43. data/spec/commandline_path_integration_spec.rb +230 -0
  44. data/spec/config_file_integration_spec.rb +362 -0
  45. data/spec/{css_spec.rb → css_dsl_spec.rb} +7 -3
  46. data/spec/css_parser_spec.rb +207 -0
  47. data/spec/document_spec.rb +37 -242
  48. data/spec/flattened_path_spec.rb +150 -0
  49. data/spec/layout_spec.rb +42 -3
  50. data/spec/mint_spec.rb +22 -217
  51. data/spec/path_handling_spec.rb +237 -0
  52. data/spec/run_cli_tests.rb +1 -1
  53. data/spec/spec_helper.rb +3 -10
  54. data/spec/style_spec.rb +31 -56
  55. data/spec/support/cli_helpers.rb +7 -10
  56. data/spec/support/matchers.rb +1 -1
  57. data/spec/template_spec.rb +31 -0
  58. data/spec/workspace_spec.rb +177 -0
  59. metadata +78 -93
  60. data/bin/mint-epub +0 -20
  61. data/config/templates/default/css/style.css +0 -205
  62. data/config/templates/garden/layout.erb +0 -38
  63. data/config/templates/garden/style.css +0 -303
  64. data/config/templates/newspaper/layout.erb +0 -16
  65. data/config/templates/nord/layout.erb +0 -11
  66. data/config/templates/nord-dark/layout.erb +0 -11
  67. data/config/templates/protocol/layout.erb +0 -9
  68. data/config/templates/protocol/style.css +0 -25
  69. data/config/templates/zen/layout.erb +0 -11
  70. data/config/templates/zen/style.css +0 -114
  71. data/lib/mint/command_line.rb +0 -360
  72. data/lib/mint/css_template.rb +0 -37
  73. data/lib/mint/markdown_template.rb +0 -47
  74. data/lib/mint/mint.rb +0 -313
  75. data/lib/mint/plugin.rb +0 -136
  76. data/lib/mint/plugins/epub.rb +0 -293
  77. data/lib/mint/resource.rb +0 -101
  78. data/plugins/templates/epub/layouts/container.haml +0 -5
  79. data/plugins/templates/epub/layouts/content.haml +0 -35
  80. data/plugins/templates/epub/layouts/layout.haml +0 -6
  81. data/plugins/templates/epub/layouts/title.haml +0 -11
  82. data/plugins/templates/epub/layouts/toc.haml +0 -26
  83. data/spec/cli/configuration_management_spec.rb +0 -363
  84. data/spec/cli/template_management_spec.rb +0 -300
  85. data/spec/helpers_spec.rb +0 -249
  86. data/spec/plugin_spec.rb +0 -449
  87. data/spec/resource_spec.rb +0 -135
@@ -0,0 +1,362 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Config File Integration" do
4
+ include CLIHelpers
5
+
6
+
7
+ describe "TOML config file support" do
8
+ context "with local config file" do
9
+ # Note: Tests run in tmp directory from spec_helper
10
+
11
+ before do
12
+ FileUtils.mkdir_p(".mint") # Ensure directory exists for each test
13
+ end
14
+
15
+ after do
16
+ cleanup_test_files("*.html", "*.css")
17
+ # Don't clean up .mint directory - let spec_helper handle it
18
+ end
19
+
20
+ it "loads template option from config file" do
21
+ File.write(".mint/config.toml", <<~TOML)
22
+ template = "custom"
23
+ TOML
24
+
25
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
26
+
27
+ expect(config.layout_name).to eq("custom")
28
+ expect(config.style_name).to eq("custom")
29
+ end
30
+
31
+ it "loads layout option from config file" do
32
+ File.write(".mint/config.toml", <<~TOML)
33
+ layout = "minimal"
34
+ TOML
35
+
36
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
37
+
38
+ expect(config.layout_name).to eq("minimal")
39
+ end
40
+
41
+ it "loads style option from config file" do
42
+ File.write(".mint/config.toml", <<~TOML)
43
+ style = "dark"
44
+ TOML
45
+
46
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
47
+
48
+ expect(config.style_name).to eq("dark")
49
+ end
50
+
51
+
52
+ it "loads output-file option from config file" do
53
+ File.write(".mint/config.toml", <<~TOML)
54
+ output-file = "%{ext}_custom.%{ext}"
55
+ TOML
56
+
57
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
58
+
59
+ expect(config.output_file_format).to eq("%{ext}_custom.%{ext}")
60
+ end
61
+
62
+ it "loads destination option from config file" do
63
+ File.write(".mint/config.toml", <<~TOML)
64
+ destination = "build"
65
+ TOML
66
+
67
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
68
+
69
+ expect(config.destination_directory).to eq(Pathname.new("build"))
70
+ end
71
+
72
+ it "loads style-mode option from config file" do
73
+ File.write(".mint/config.toml", <<~TOML)
74
+ style-mode = "external"
75
+ TOML
76
+
77
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
78
+
79
+ expect(config.style_mode).to eq(:external)
80
+ end
81
+
82
+ it "loads style-destination option from config file" do
83
+ File.write(".mint/config.toml", <<~TOML)
84
+ style-destination = "assets/css"
85
+ TOML
86
+
87
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
88
+
89
+ expect(config.style_destination_directory).to eq("assets/css")
90
+ end
91
+
92
+ it "loads preserve-structure option from config file" do
93
+ File.write(".mint/config.toml", <<~TOML)
94
+ preserve-structure = true
95
+ TOML
96
+
97
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
98
+
99
+ expect(config.preserve_structure).to be true
100
+ end
101
+
102
+ it "loads navigation option from config file" do
103
+ File.write(".mint/config.toml", <<~TOML)
104
+ navigation = true
105
+ TOML
106
+
107
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
108
+
109
+ expect(config.navigation).to be true
110
+ end
111
+
112
+
113
+ it "loads navigation-depth option from config file" do
114
+ File.write(".mint/config.toml", <<~TOML)
115
+ navigation-depth = 5
116
+ TOML
117
+
118
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
119
+
120
+ expect(config.navigation_depth).to eq(5)
121
+ end
122
+
123
+ it "loads navigation-title option from config file" do
124
+ File.write(".mint/config.toml", <<~TOML)
125
+ navigation-title = "Custom Navigation"
126
+ TOML
127
+
128
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
129
+
130
+ expect(config.navigation_title).to eq("Custom Navigation")
131
+ end
132
+
133
+ it "loads autodrop option from config file" do
134
+ File.write(".mint/config.toml", <<~TOML)
135
+ autodrop = false
136
+ TOML
137
+
138
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
139
+
140
+ expect(config.autodrop).to be false
141
+ end
142
+
143
+ it "loads insert-title-heading option from config file" do
144
+ File.write(".mint/config.toml", <<~TOML)
145
+ insert-title-heading = true
146
+ TOML
147
+
148
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
149
+
150
+ expect(config.insert_title_heading).to be true
151
+ end
152
+
153
+ it "loads multiple options from config file" do
154
+ File.write(".mint/config.toml", <<~TOML)
155
+ template = "blog"
156
+ destination = "public"
157
+ style-mode = "external"
158
+ preserve-structure = true
159
+ navigation = true
160
+ navigation-depth = 2
161
+ insert-title-heading = true
162
+ TOML
163
+
164
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
165
+
166
+ expect(config.layout_name).to eq("blog")
167
+ expect(config.style_name).to eq("blog")
168
+ expect(config.destination_directory).to eq(Pathname.new("public"))
169
+ expect(config.style_mode).to eq(:external)
170
+ expect(config.preserve_structure).to be true
171
+ expect(config.navigation).to be true
172
+ expect(config.navigation_depth).to eq(2)
173
+ expect(config.insert_title_heading).to be true
174
+ end
175
+
176
+ context "command-line options override config file" do
177
+ before do
178
+ File.write(".mint/config.toml", <<~TOML)
179
+ template = "config"
180
+ destination = "config-dest"
181
+ style-mode = "external"
182
+ preserve-structure = true
183
+ navigation-depth = 5
184
+ TOML
185
+ end
186
+
187
+ it "command-line template overrides config file template" do
188
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--template", "cli", "test.md"])
189
+
190
+ expect(config.layout_name).to eq("cli")
191
+ expect(config.style_name).to eq("cli")
192
+ end
193
+
194
+ it "command-line layout overrides config file template layout" do
195
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--layout", "cli-layout", "test.md"])
196
+
197
+ expect(config.layout_name).to eq("cli-layout")
198
+ expect(config.style_name).to eq("config") # should still use config for style
199
+ end
200
+
201
+ it "command-line destination overrides config file destination" do
202
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--destination", "cli-dest", "test.md"])
203
+
204
+ expect(config.destination_directory).to eq(Pathname.new("cli-dest"))
205
+ end
206
+
207
+ it "command-line style-mode overrides config file style-mode" do
208
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--style-mode", "inline", "test.md"])
209
+
210
+ expect(config.style_mode).to eq(:inline)
211
+ end
212
+
213
+ it "command-line preserve-structure overrides config file preserve-structure" do
214
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
215
+
216
+ expect(config.preserve_structure).to be true # from config
217
+ end
218
+
219
+ it "command-line navigation-depth overrides config file navigation-depth" do
220
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--navigation-depth", "3", "test.md"])
221
+
222
+ expect(config.navigation_depth).to eq(3)
223
+ end
224
+ end
225
+
226
+ context "--no- flags override config file boolean values" do
227
+ before do
228
+ File.write(".mint/config.toml", <<~TOML)
229
+ preserve-structure = true
230
+ navigation = true
231
+ insert-title-heading = true
232
+ TOML
233
+ end
234
+
235
+ it "--no-preserve-structure overrides config file preserve-structure=true" do
236
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--no-preserve-structure", "test.md"])
237
+
238
+ expect(config.preserve_structure).to be false
239
+ end
240
+
241
+ it "--no-navigation overrides config file navigation=true" do
242
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--no-navigation", "test.md"])
243
+
244
+ expect(config.navigation).to be false
245
+ end
246
+
247
+ it "--no-insert-title-heading overrides config file insert-title-heading=true" do
248
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--no-insert-title-heading", "test.md"])
249
+
250
+ expect(config.insert_title_heading).to be false
251
+ end
252
+
253
+ it "positive flags still work to override config file false values" do
254
+ File.write(".mint/config.toml", <<~TOML)
255
+ preserve-structure = false
256
+ navigation = false
257
+ insert-title-heading = false
258
+ TOML
259
+
260
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--preserve-structure", "--navigation", "--insert-title-heading", "test.md"])
261
+
262
+ expect(config.preserve_structure).to be true
263
+ expect(config.navigation).to be true
264
+ expect(config.insert_title_heading).to be true
265
+ end
266
+
267
+ it "combines positive and negative flags" do
268
+ command, config, files, help = Mint::Commandline.parse!(["publish", "--preserve-structure", "--no-navigation", "test.md"])
269
+
270
+ expect(config.preserve_structure).to be true # overridden by CLI flag
271
+ expect(config.navigation).to be false # overridden by --no- flag
272
+ expect(config.insert_title_heading).to be true # from config file
273
+ end
274
+ end
275
+
276
+ it "handles boolean values correctly" do
277
+ File.write(".mint/config.toml", <<~TOML)
278
+ preserve-structure = false
279
+ navigation = false
280
+ insert-title-heading = false
281
+ TOML
282
+
283
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
284
+
285
+ expect(config.preserve_structure).to be false
286
+ expect(config.navigation).to be false
287
+ expect(config.insert_title_heading).to be false
288
+ end
289
+
290
+ it "handles integer values correctly" do
291
+ File.write(".mint/config.toml", <<~TOML)
292
+ navigation-depth = 10
293
+ TOML
294
+
295
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
296
+
297
+ expect(config.navigation_depth).to eq(10)
298
+ end
299
+
300
+ it "handles missing config file gracefully" do
301
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
302
+
303
+ expect(config.layout_name).to eq("default")
304
+ expect(config.style_name).to eq("default")
305
+ expect(config.preserve_structure).to be true
306
+ expect(config.navigation).to be false
307
+ end
308
+
309
+ it "handles empty config file gracefully" do
310
+ File.write(".mint/config.toml", "")
311
+
312
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
313
+
314
+ expect(config.layout_name).to eq("default")
315
+ expect(config.style_name).to eq("default")
316
+ end
317
+
318
+ it "handles config file with comments" do
319
+ File.write(".mint/config.toml", <<~TOML)
320
+ # This is a comment
321
+ template = "documented" # inline comment
322
+
323
+ # Another section
324
+ destination = "output" # destination comment
325
+ TOML
326
+
327
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
328
+
329
+ expect(config.layout_name).to eq("documented")
330
+ expect(config.style_name).to eq("documented")
331
+ expect(config.destination_directory).to eq(Pathname.new("output"))
332
+ end
333
+ end
334
+
335
+ context "config file scope priority" do
336
+ before do
337
+ FileUtils.mkdir_p(".mint")
338
+ FileUtils.mkdir_p(File.expand_path("~/.config/mint"))
339
+ end
340
+
341
+ after do
342
+ cleanup_test_files(".mint", File.expand_path("~/.config/mint/config.toml"))
343
+ end
344
+
345
+ it "local config overrides user config" do
346
+ File.write(File.expand_path("~/.config/mint/config.toml"), <<~TOML)
347
+ template = "user"
348
+ destination = "user-dest"
349
+ TOML
350
+
351
+ File.write(".mint/config.toml", <<~TOML)
352
+ template = "local"
353
+ TOML
354
+
355
+ command, config, files, help = Mint::Commandline.parse!(["publish", "test.md"])
356
+
357
+ expect(config.layout_name).to eq("local") # local overrides user
358
+ expect(config.destination_directory).to eq(Pathname.new("user-dest")) # user config still applies for non-overridden values
359
+ end
360
+ end
361
+ end
362
+ end
@@ -31,15 +31,19 @@ module Mint
31
31
  # "Bullet: checkbox.png" => "li { list-style-image: url(checkbox.png) }",
32
32
  }
33
33
 
34
- table.each do |human, machine|
35
- CSS.stylify(*human.split(":").map(&:strip))
34
+ table.each do |human, expected|
35
+ key, value = human.split(":").map(&:strip)
36
+ actual = CSS.stylify(key, value)
37
+ expect(actual).to eq(expected), "Expected '#{human}' to produce '#{expected}', got '#{actual}'"
36
38
  end
37
39
  end
38
40
  end
39
41
 
40
42
  describe ".parse" do
41
43
  it "transforms a map of human-readable styles into a CSS string" do
42
- expect(CSS.parse({ "Font" => "Helvetica" })).to eq("#container {\n font-family: Helvetica;\n}")
44
+ result = CSS.parse({ "Font" => "Helvetica" })
45
+ expect(result).to include("container")
46
+ expect(result).to include("font-family: Helvetica")
43
47
  end
44
48
  end
45
49
  end
@@ -0,0 +1,207 @@
1
+ require "spec_helper"
2
+ require "mint/css_parser"
3
+ require "tempfile"
4
+ require "pathname"
5
+
6
+ describe Mint::CssParser do
7
+ describe ".extract_imports" do
8
+ it "extracts @import statements with double quotes" do
9
+ css = '@import "reset.css"; body { margin: 0; }'
10
+ imports = Mint::CssParser.extract_imports(css)
11
+ expect(imports).to eq(["reset.css"])
12
+ end
13
+
14
+ it "extracts @import statements with single quotes" do
15
+ css = "@import 'normalize.css'; .class { color: red; }"
16
+ imports = Mint::CssParser.extract_imports(css)
17
+ expect(imports).to eq(["normalize.css"])
18
+ end
19
+
20
+ it "extracts @import url() statements" do
21
+ css = '@import url("fonts.css"); @import url(\'colors.css\');'
22
+ imports = Mint::CssParser.extract_imports(css)
23
+ expect(imports).to eq(["fonts.css", "colors.css"])
24
+ end
25
+
26
+ it "extracts multiple @import statements" do
27
+ css = <<~CSS
28
+ @import "reset.css";
29
+ @import 'normalize.css';
30
+ @import url("fonts.css");
31
+ body { margin: 0; }
32
+ CSS
33
+ imports = Mint::CssParser.extract_imports(css)
34
+ expect(imports).to eq(["reset.css", "normalize.css", "fonts.css"])
35
+ end
36
+
37
+ it "returns empty array when no imports found" do
38
+ css = "body { margin: 0; color: blue; }"
39
+ imports = Mint::CssParser.extract_imports(css)
40
+ expect(imports).to eq([])
41
+ end
42
+
43
+ it "ignores commented out @import statements" do
44
+ css = <<~CSS
45
+ /* @import "commented.css"; */
46
+ @import "active.css";
47
+ body {
48
+ /* @import url("also-commented.css"); */
49
+ margin: 0;
50
+ }
51
+ CSS
52
+ imports = Mint::CssParser.extract_imports(css)
53
+ expect(imports).to eq(["active.css"])
54
+ end
55
+
56
+ it "ignores multi-line commented imports" do
57
+ css = <<~CSS
58
+ /*
59
+ * @import "multi-line-comment.css";
60
+ * @import 'another-commented.css';
61
+ */
62
+ @import "valid.css";
63
+ CSS
64
+ imports = Mint::CssParser.extract_imports(css)
65
+ expect(imports).to eq(["valid.css"])
66
+ end
67
+ end
68
+
69
+ describe ".resolve_css_files" do
70
+ let(:temp_dir) { Dir.mktmpdir }
71
+
72
+ after do
73
+ FileUtils.rm_rf(temp_dir)
74
+ end
75
+
76
+ it "resolves main CSS file path relative to HTML output" do
77
+ # Create directory structure:
78
+ # temp_dir/
79
+ # css/
80
+ # main.css
81
+ # output/
82
+ # index.html (output file)
83
+
84
+ css_dir = File.join(temp_dir, "css")
85
+ output_dir = File.join(temp_dir, "output")
86
+ FileUtils.mkdir_p([css_dir, output_dir])
87
+
88
+ main_css = File.join(css_dir, "main.css")
89
+ html_output = File.join(output_dir, "index.html")
90
+
91
+ File.write(main_css, "body { margin: 0; }")
92
+
93
+ css_files = Mint::CssParser.resolve_css_files(main_css, html_output)
94
+ expect(css_files).to eq(["../css/main.css"])
95
+ end
96
+
97
+ it "resolves main CSS and imported files" do
98
+ # Create directory structure:
99
+ # temp_dir/
100
+ # css/
101
+ # main.css (imports reset.css)
102
+ # reset.css
103
+ # output/
104
+ # index.html
105
+
106
+ css_dir = File.join(temp_dir, "css")
107
+ output_dir = File.join(temp_dir, "output")
108
+ FileUtils.mkdir_p([css_dir, output_dir])
109
+
110
+ main_css = File.join(css_dir, "main.css")
111
+ reset_css = File.join(css_dir, "reset.css")
112
+ html_output = File.join(output_dir, "index.html")
113
+
114
+ File.write(main_css, '@import "reset.css"; body { margin: 0; }')
115
+ File.write(reset_css, "* { box-sizing: border-box; }")
116
+
117
+ css_files = Mint::CssParser.resolve_css_files(main_css, html_output)
118
+ expect(css_files).to eq(["../css/reset.css", "../css/main.css"])
119
+ end
120
+
121
+ it "ignores non-existent imported files" do
122
+ css_dir = File.join(temp_dir, "css")
123
+ output_dir = File.join(temp_dir, "output")
124
+ FileUtils.mkdir_p([css_dir, output_dir])
125
+
126
+ main_css = File.join(css_dir, "main.css")
127
+ html_output = File.join(output_dir, "index.html")
128
+
129
+ File.write(main_css, '@import "nonexistent.css"; body { margin: 0; }')
130
+
131
+ css_files = Mint::CssParser.resolve_css_files(main_css, html_output)
132
+ expect(css_files).to eq(["../css/main.css"])
133
+ end
134
+
135
+ it "only processes .css files" do
136
+ scss_dir = File.join(temp_dir, "scss")
137
+ output_dir = File.join(temp_dir, "output")
138
+ FileUtils.mkdir_p([scss_dir, output_dir])
139
+
140
+ main_scss = File.join(scss_dir, "main.scss")
141
+ html_output = File.join(output_dir, "index.html")
142
+
143
+ File.write(main_scss, '@import "reset"; body { margin: 0; }')
144
+
145
+ css_files = Mint::CssParser.resolve_css_files(main_scss, html_output)
146
+ expect(css_files).to eq(["../scss/main.scss"])
147
+ end
148
+
149
+ it "places imported CSS files before main CSS file for correct cascade order" do
150
+ # Create directory structure:
151
+ # temp_dir/
152
+ # css/
153
+ # base.css (imports reset.css and fonts.css)
154
+ # reset.css
155
+ # fonts.css
156
+ # output/
157
+ # index.html
158
+
159
+ css_dir = File.join(temp_dir, "css")
160
+ output_dir = File.join(temp_dir, "output")
161
+ FileUtils.mkdir_p([css_dir, output_dir])
162
+
163
+ base_css = File.join(css_dir, "base.css")
164
+ reset_css = File.join(css_dir, "reset.css")
165
+ fonts_css = File.join(css_dir, "fonts.css")
166
+ html_output = File.join(output_dir, "index.html")
167
+
168
+ File.write(base_css, '@import "reset.css"; @import "fonts.css"; body { margin: 0; }')
169
+ File.write(reset_css, "* { box-sizing: border-box; }")
170
+ File.write(fonts_css, "@font-face { font-family: 'MyFont'; }")
171
+
172
+ css_files = Mint::CssParser.resolve_css_files(base_css, html_output)
173
+
174
+ # Imports should come first, then the main file
175
+ expect(css_files).to eq([
176
+ "../css/reset.css",
177
+ "../css/fonts.css",
178
+ "../css/base.css"
179
+ ])
180
+ end
181
+ end
182
+
183
+ describe ".generate_link_tags" do
184
+ it "generates HTML link tags for CSS files" do
185
+ css_paths = ["../css/main.css", "../css/reset.css"]
186
+
187
+ html = Mint::CssParser.generate_link_tags(css_paths)
188
+
189
+ expected = <<~HTML.strip
190
+ <link rel="stylesheet" href="../css/main.css">
191
+ <link rel="stylesheet" href="../css/reset.css">
192
+ HTML
193
+
194
+ expect(html).to eq(expected)
195
+ end
196
+
197
+ it "handles empty array" do
198
+ html = Mint::CssParser.generate_link_tags([])
199
+ expect(html).to eq("")
200
+ end
201
+
202
+ it "handles single CSS file" do
203
+ html = Mint::CssParser.generate_link_tags(["styles.css"])
204
+ expect(html).to eq('<link rel="stylesheet" href="styles.css">')
205
+ end
206
+ end
207
+ end