mint 0.8.1 → 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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -26
  3. data/README.md +117 -37
  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 +45 -25
  23. data/lib/mint/document.rb +250 -365
  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 +85 -44
  37. data/spec/cli/README.md +2 -2
  38. data/spec/cli/argument_parsing_spec.rb +89 -147
  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 +59 -1
  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 +75 -89
  60. data/bin/mint-epub +0 -20
  61. data/config/templates/garden/layout.erb +0 -38
  62. data/config/templates/garden/style.css +0 -303
  63. data/config/templates/nord/layout.erb +0 -11
  64. data/config/templates/nord-dark/layout.erb +0 -11
  65. data/config/templates/zen/layout.erb +0 -11
  66. data/config/templates/zen/style.css +0 -114
  67. data/lib/mint/command_line.rb +0 -360
  68. data/lib/mint/css_template.rb +0 -37
  69. data/lib/mint/markdown_template.rb +0 -47
  70. data/lib/mint/mint.rb +0 -313
  71. data/lib/mint/plugin.rb +0 -136
  72. data/lib/mint/plugins/epub.rb +0 -293
  73. data/lib/mint/resource.rb +0 -101
  74. data/plugins/templates/epub/layouts/container.haml +0 -5
  75. data/plugins/templates/epub/layouts/content.haml +0 -35
  76. data/plugins/templates/epub/layouts/layout.haml +0 -6
  77. data/plugins/templates/epub/layouts/title.haml +0 -11
  78. data/plugins/templates/epub/layouts/toc.haml +0 -26
  79. data/spec/cli/configuration_management_spec.rb +0 -363
  80. data/spec/cli/template_management_spec.rb +0 -300
  81. data/spec/helpers_spec.rb +0 -249
  82. data/spec/plugin_spec.rb +0 -449
  83. data/spec/resource_spec.rb +0 -135
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  RSpec.describe "CLI Publishing Workflow" do
4
- describe "Mint::CommandLine.publish!" do
4
+ describe "Mint::Commandline.publish!" do
5
5
  context "in isolated environment" do
6
6
  around(:each) do |example|
7
7
  in_temp_dir do |dir|
@@ -14,10 +14,10 @@ RSpec.describe "CLI Publishing Workflow" do
14
14
 
15
15
  describe "basic publishing" do
16
16
  it "publishes a single markdown file" do
17
- markdown_file = create_markdown_file("test.md", "# Hello World\n\nThis is a test.")
17
+ markdown_path = create_markdown_path("test.md", "# Hello World\n\nThis is a test.")
18
18
 
19
19
  expect {
20
- Mint::CommandLine.publish!([markdown_file], {})
20
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.defaults)
21
21
  }.not_to raise_error
22
22
 
23
23
  verify_file_content("test.html") do |content|
@@ -27,11 +27,11 @@ RSpec.describe "CLI Publishing Workflow" do
27
27
  end
28
28
 
29
29
  it "publishes multiple markdown files" do
30
- file1 = create_markdown_file("doc1.md", "# Document 1")
31
- file2 = create_markdown_file("doc2.md", "# Document 2")
30
+ file1 = create_markdown_path("doc1.md", "# Document 1")
31
+ file2 = create_markdown_path("doc2.md", "# Document 2")
32
32
 
33
33
  expect {
34
- Mint::CommandLine.publish!([file1, file2], {})
34
+ Mint::Commandline.publish!([Pathname.new(file1), Pathname.new(file2)], config: Mint::Config.defaults)
35
35
  }.not_to raise_error
36
36
 
37
37
  verify_file_content("doc1.html") do |content|
@@ -44,9 +44,9 @@ RSpec.describe "CLI Publishing Workflow" do
44
44
  end
45
45
 
46
46
  it "uses default template when none specified" do
47
- markdown_file = create_markdown_file("test.md", "# Test")
47
+ markdown_path = create_markdown_path("test.md", "# Test")
48
48
 
49
- Mint::CommandLine.publish!([markdown_file], {})
49
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.defaults)
50
50
 
51
51
  verify_file_content("test.html") do |content|
52
52
  expect(content).to include("<!DOCTYPE html>")
@@ -58,10 +58,10 @@ RSpec.describe "CLI Publishing Workflow" do
58
58
 
59
59
  describe "with custom options" do
60
60
  it "publishes with custom destination" do
61
- markdown_file = create_markdown_file("test.md", "# Test")
61
+ markdown_path = create_markdown_path("test.md", "# Test")
62
62
  FileUtils.mkdir_p("output")
63
63
 
64
- Mint::CommandLine.publish!([markdown_file], { destination: "output" })
64
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.with_defaults(destination_directory: Pathname.new("output")))
65
65
 
66
66
  expect(File.exist?("output/test.html")).to be true
67
67
  expect(File.exist?("test.html")).to be false
@@ -71,11 +71,11 @@ RSpec.describe "CLI Publishing Workflow" do
71
71
  # Create a subdirectory structure
72
72
  FileUtils.mkdir_p("docs")
73
73
  Dir.chdir("docs") do
74
- create_markdown_file("readme.md", "# Documentation")
74
+ create_markdown_path("readme.md", "# Documentation")
75
75
  end
76
76
 
77
77
  # Publish from parent directory with current directory as root
78
- Mint::CommandLine.publish!(["docs/readme.md"], { root: Dir.getwd })
78
+ Mint::Commandline.publish!([Pathname.new("docs/readme.md")], config: Mint::Config.with_defaults(working_directory: Pathname.getwd, preserve_structure: true))
79
79
 
80
80
  expect(File.exist?("docs/readme.html")).to be true
81
81
  end
@@ -85,9 +85,9 @@ RSpec.describe "CLI Publishing Workflow" do
85
85
  File.write(".mint/templates/custom/layout.erb",
86
86
  "<html><body class='custom'><%= content %></body></html>")
87
87
 
88
- markdown_file = create_markdown_file("test.md", "# Test")
88
+ markdown_path = create_markdown_path("test.md", "# Test")
89
89
 
90
- Mint::CommandLine.publish!([markdown_file], { layout: "custom" })
90
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.with_defaults(layout_name: "custom"))
91
91
 
92
92
  verify_file_content("test.html") do |content|
93
93
  expect(content).to include("class='custom'")
@@ -99,9 +99,9 @@ RSpec.describe "CLI Publishing Workflow" do
99
99
  File.write(".mint/templates/styled/style.css",
100
100
  "body { background: red; }")
101
101
 
102
- markdown_file = create_markdown_file("test.md", "# Test")
102
+ markdown_path = create_markdown_path("test.md", "# Test")
103
103
 
104
- Mint::CommandLine.publish!([markdown_file], { style: "styled" })
104
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.with_defaults(style_name: "styled"))
105
105
 
106
106
  # Check if style file was created and linked
107
107
  expect(File.exist?("test.html")).to be true
@@ -115,39 +115,45 @@ RSpec.describe "CLI Publishing Workflow" do
115
115
  FileUtils.mkdir_p("docs/section1")
116
116
  FileUtils.mkdir_p("docs/section2")
117
117
 
118
- create_markdown_file("docs/index.md", "# Main Documentation")
119
- create_markdown_file("docs/section1/intro.md", "# Introduction")
120
- create_markdown_file("docs/section2/advanced.md", "# Advanced Topics")
118
+ create_markdown_path("docs/index.md", "# Main Documentation")
119
+ create_markdown_path("docs/section1/intro.md", "# Introduction")
120
+ create_markdown_path("docs/section2/advanced.md", "# Advanced Topics")
121
121
 
122
122
  # Also create non-markdown files that should be ignored
123
123
  File.write("docs/config.yaml", "key: value")
124
124
  File.write("docs/section1/script.js", "console.log('test');")
125
125
 
126
- Mint::CommandLine.publish!(["docs"], { recursive: true })
126
+ # Find all markdown files and process them explicitly since recursive option was removed
127
+ md_files = Dir.glob("docs/**/*.md").map {|f| Pathname.new(f) }
128
+ Mint::Commandline.publish!(md_files, config: Mint::Config.with_defaults(preserve_structure: true))
127
129
 
128
- expect(File.exist?("docs/index.html")).to be true
129
- expect(File.exist?("docs/section1/intro.html")).to be true
130
- expect(File.exist?("docs/section2/advanced.html")).to be true
130
+ expect(File.exist?("index.html")).to be true
131
+ expect(File.exist?("section1/intro.html")).to be true
132
+ expect(File.exist?("section2/advanced.html")).to be true
131
133
 
132
134
  # Non-markdown files should not be converted
133
135
  expect(File.exist?("docs/config.html")).to be false
134
136
  expect(File.exist?("docs/section1/script.html")).to be false
135
137
  end
136
138
 
137
- it "handles empty directories gracefully" do
139
+ it "raises an error when no files are specified" do
138
140
  FileUtils.mkdir_p("empty/nested/dirs")
139
141
 
140
142
  expect {
141
- Mint::CommandLine.publish!(["empty"], { recursive: true })
142
- }.not_to raise_error
143
+ # Process empty directory - should raise an error
144
+ md_files = Dir.glob("empty/**/*.md").map {|f| Pathname.new(f) }
145
+ Mint::Commandline.publish!(md_files, config: Mint::Config.with_defaults(preserve_structure: true))
146
+ }.to raise_error(ArgumentError, "No files specified. Use file paths or '-' to read from STDIN.")
143
147
  end
144
148
 
145
149
  it "processes current directory when no files specified" do
146
- create_markdown_file("current.md", "# Current Directory")
150
+ create_markdown_path("current.md", "# Current Directory")
147
151
  FileUtils.mkdir_p("sub")
148
- create_markdown_file("sub/nested.md", "# Nested File")
152
+ create_markdown_path("sub/nested.md", "# Nested File")
149
153
 
150
- Mint::CommandLine.publish!([], { recursive: true })
154
+ # Process all markdown files in current directory and subdirectories
155
+ md_files = Dir.glob("**/*.md").map {|f| Pathname.new(f) }
156
+ Mint::Commandline.publish!(md_files, config: Mint::Config.with_defaults(preserve_structure: true))
151
157
 
152
158
  expect(File.exist?("current.html")).to be true
153
159
  expect(File.exist?("sub/nested.html")).to be true
@@ -159,11 +165,11 @@ RSpec.describe "CLI Publishing Workflow" do
159
165
  # Create files with different markdown extensions
160
166
  extensions = %w[md markdown mkd]
161
167
  extensions.each_with_index do |ext, i|
162
- create_markdown_file("test#{i}.#{ext}", "# Test #{i}")
168
+ create_markdown_path("test#{i}.#{ext}", "# Test #{i}")
163
169
  end
164
170
 
165
- files = extensions.map.with_index {|ext, i| "test#{i}.#{ext}" }
166
- Mint::CommandLine.publish!(files, {})
171
+ files = extensions.map.with_index {|ext, i| Pathname.new("test#{i}.#{ext}") }
172
+ Mint::Commandline.publish!(files, config: Mint::Config.defaults)
167
173
 
168
174
  extensions.each_with_index do |ext, i|
169
175
  expect(File.exist?("test#{i}.html")).to be true
@@ -196,9 +202,9 @@ RSpec.describe "CLI Publishing Workflow" do
196
202
  [Link to example](https://example.com)
197
203
  MARKDOWN
198
204
 
199
- create_markdown_file("complex.md", complex_content)
205
+ create_markdown_path("complex.md", complex_content)
200
206
 
201
- Mint::CommandLine.publish!(["complex.md"], {})
207
+ Mint::Commandline.publish!([Pathname.new("complex.md")], config: Mint::Config.defaults)
202
208
 
203
209
  verify_file_content("complex.html") do |content|
204
210
  expect(content).to include("<h1>Main Title</h1>")
@@ -215,36 +221,26 @@ RSpec.describe "CLI Publishing Workflow" do
215
221
  describe "error handling" do
216
222
  it "handles missing source files gracefully" do
217
223
  expect {
218
- Mint::CommandLine.publish!(["nonexistent.md"], {})
224
+ Mint::Commandline.publish!([Pathname.new("nonexistent.md")], config: Mint::Config.defaults)
219
225
  }.to raise_error(Errno::ENOENT) # Should raise an error for missing file
220
226
  end
221
227
 
222
- it "handles permission errors" do
223
- # Create a file, then make directory read-only
224
- markdown_file = create_markdown_file("test.md", "# Test")
225
-
226
- # Try to publish to a non-writable location
227
- # This test might be platform-specific
228
- expect {
229
- Mint::CommandLine.publish!([markdown_file], { destination: "/root" })
230
- }.to raise_error(Errno::EROFS) # Should fail due to permissions
231
- end
232
-
233
- it "handles invalid templates gracefully" do
234
- markdown_file = create_markdown_file("test.md", "# Test")
228
+ it "handles invalid templates by throwing error" do
229
+ markdown_path = create_markdown_path("test.md", "# Test")
235
230
 
231
+ # Should throw error when user specifies nonexistent style
236
232
  expect {
237
- Mint::CommandLine.publish!([markdown_file], { layout: "nonexistent" })
238
- }.to raise_error(Mint::TemplateNotFoundException)
233
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.with_defaults(style_name: "nonexistent"))
234
+ }.to raise_error(Mint::StyleNotFoundException)
239
235
  end
240
236
  end
241
237
 
242
238
  describe "output file naming" do
243
239
  it "preserves directory structure in output" do
244
240
  FileUtils.mkdir_p("input/subdir")
245
- create_markdown_file("input/subdir/doc.md", "# Nested Document")
241
+ create_markdown_path("input/subdir/doc.md", "# Nested Document")
246
242
 
247
- Mint::CommandLine.publish!(["input/subdir/doc.md"], {})
243
+ Mint::Commandline.publish!([Pathname.new("input/subdir/doc.md")], config: Mint::Config.with_defaults(preserve_structure: true))
248
244
 
249
245
  expect(File.exist?("input/subdir/doc.html")).to be true
250
246
  end
@@ -257,10 +253,10 @@ RSpec.describe "CLI Publishing Workflow" do
257
253
  end
258
254
 
259
255
  it "overwrites existing output files" do
260
- markdown_file = create_markdown_file("test.md", "# Version 1")
256
+ markdown_path = create_markdown_path("test.md", "# Version 1")
261
257
  File.write("test.html", "<html>Old content</html>")
262
258
 
263
- Mint::CommandLine.publish!([markdown_file], {})
259
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.defaults)
264
260
 
265
261
  verify_file_content("test.html") do |content|
266
262
  expect(content).to include("Version 1")
@@ -272,35 +268,41 @@ RSpec.describe "CLI Publishing Workflow" do
272
268
  describe "configuration integration" do
273
269
  it "respects configuration file settings" do
274
270
  # Create custom config
275
- config_content = {
276
- 'layout' => 'custom',
277
- 'style' => 'minimal',
278
- 'destination' => 'build'
279
- }
280
- File.write(".mint/config.yaml", config_content.to_yaml)
271
+ File.write(".mint/config.toml", <<~TOML)
272
+ layout = "custom"
273
+ style = "minimal"
274
+ destination = "build"
275
+ TOML
281
276
 
282
277
  # Create the referenced templates
283
278
  create_template_directory("custom")
284
279
  create_template_directory("minimal")
285
280
  FileUtils.mkdir_p("build")
286
281
 
287
- markdown_file = create_markdown_file("test.md", "# Test")
282
+ markdown_path = create_markdown_path("test.md", "# Test")
283
+
284
+ # Load configuration from file and convert string paths to Pathnames
285
+ loaded_config = Mint.configuration
286
+ config_with_pathnames = Mint::Config.with_defaults(
287
+ layout_name: loaded_config.layout_name,
288
+ style_name: loaded_config.style_name,
289
+ destination_directory: Pathname.new(loaded_config.destination_directory.to_s)
290
+ )
288
291
 
289
- Mint::CommandLine.publish!([markdown_file], {})
292
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: config_with_pathnames)
290
293
 
291
294
  expect(File.exist?("build/test.html")).to be true
292
295
  end
293
296
 
294
297
  it "allows command-line options to override config" do
295
298
  # Set config with default destination
296
- config_content = { 'destination' => 'config_output' }
297
- File.write(".mint/config.yaml", config_content.to_yaml)
299
+ File.write(".mint/config.toml", 'destination = "config_output"')
298
300
 
299
301
  FileUtils.mkdir_p("cli_output")
300
- markdown_file = create_markdown_file("test.md", "# Test")
302
+ markdown_path = create_markdown_path("test.md", "# Test")
301
303
 
302
304
  # Override with CLI option
303
- Mint::CommandLine.publish!([markdown_file], { destination: "cli_output" })
305
+ Mint::Commandline.publish!([Pathname.new(markdown_path)], config: Mint::Config.with_defaults(destination_directory: Pathname.new("cli_output")))
304
306
 
305
307
  expect(File.exist?("cli_output/test.html")).to be true
306
308
  expect(File.exist?("config_output/test.html")).to be false
@@ -311,11 +313,11 @@ RSpec.describe "CLI Publishing Workflow" do
311
313
  it "processes multiple files efficiently" do
312
314
  files = []
313
315
  10.times do |i|
314
- files << create_markdown_file("doc#{i}.md", "# Document #{i}")
316
+ files << Pathname.new(create_markdown_path("doc#{i}.md", "# Document #{i}"))
315
317
  end
316
318
 
317
319
  start_time = Time.now
318
- Mint::CommandLine.publish!(files, {})
320
+ Mint::Commandline.publish!(files, config: Mint::Config.defaults)
319
321
  end_time = Time.now
320
322
 
321
323
  # All files should be processed
@@ -331,7 +333,7 @@ RSpec.describe "CLI Publishing Workflow" do
331
333
  # This tests the all_files feature for multi-file processing
332
334
  files = []
333
335
  3.times do |i|
334
- files << create_markdown_file("page#{i}.md", "# Page #{i}")
336
+ files << Pathname.new(create_markdown_path("page#{i}.md", "# Page #{i}"))
335
337
  end
336
338
 
337
339
  # Create a template that uses the all_files variable
@@ -353,7 +355,7 @@ RSpec.describe "CLI Publishing Workflow" do
353
355
  FileUtils.mkdir_p(".mint/templates/nav")
354
356
  File.write(".mint/templates/nav/layout.erb", nav_template)
355
357
 
356
- Mint::CommandLine.publish!(files, { layout: "nav" })
358
+ Mint::Commandline.publish!(files, config: Mint::Config.with_defaults(layout_name: "nav", navigation: true))
357
359
 
358
360
  # Check that navigation was included
359
361
  verify_file_content("page0.html") do |content|
@@ -0,0 +1,230 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Mint::Commandline.publish! Path Integration" do
4
+ context "in isolated environment" do
5
+ around(:each) do |example|
6
+ in_temp_dir do |dir|
7
+ @test_dir = dir
8
+ create_template_directory("default")
9
+ example.run
10
+ end
11
+ end
12
+
13
+ describe "batch file processing with mixed paths" do
14
+ it "handles mixed relative and nested paths in single batch" do
15
+ FileUtils.mkdir_p(["docs/api", "content/blog", "output"])
16
+
17
+ files = [
18
+ Pathname.new("readme.md"),
19
+ Pathname.new("docs/installation.md"),
20
+ Pathname.new("docs/api/reference.md"),
21
+ Pathname.new("content/blog/post1.md")
22
+ ]
23
+
24
+ files.each_with_index do |file, i|
25
+ create_markdown_path(file, "# Document #{i + 1}")
26
+ end
27
+
28
+ config = Mint::Config.with_defaults(destination_directory: Pathname.new("output"), preserve_structure: true)
29
+ Mint::Commandline.publish!(files, config: config)
30
+
31
+ expect(File.exist?("output/readme.html")).to be true
32
+ expect(File.exist?("output/docs/installation.html")).to be true
33
+ expect(File.exist?("output/docs/api/reference.html")).to be true
34
+ expect(File.exist?("output/content/blog/post1.html")).to be true
35
+ end
36
+
37
+ it "handles glob patterns maintaining directory structure" do
38
+ FileUtils.mkdir_p(["guides/beginner", "guides/advanced", "tutorials", "site"])
39
+
40
+ create_markdown_path("guides/beginner/basics.md", "# Basics")
41
+ create_markdown_path("guides/beginner/setup.md", "# Setup")
42
+ create_markdown_path("guides/advanced/config.md", "# Configuration")
43
+ create_markdown_path("tutorials/first-steps.md", "# First Steps")
44
+
45
+ files = Dir.glob("**/*.md").map {|f| Pathname.new(f) }
46
+ config = Mint::Config.with_defaults(destination_directory: Pathname.new("site"), preserve_structure: true)
47
+
48
+ Mint::Commandline.publish!(files, config: config)
49
+
50
+ expect(File.exist?("site/guides/beginner/basics.html")).to be true
51
+ expect(File.exist?("site/guides/beginner/setup.html")).to be true
52
+ expect(File.exist?("site/guides/advanced/config.html")).to be true
53
+ expect(File.exist?("site/tutorials/first-steps.html")).to be true
54
+ end
55
+ end
56
+
57
+ describe "root directory configuration effects" do
58
+ it "processes files with explicit root directory in batch" do
59
+ FileUtils.mkdir_p(["source/pages", "source/assets", "build"])
60
+
61
+ files = [
62
+ Pathname.new("source/pages/home.md"),
63
+ Pathname.new("source/pages/about.md"),
64
+ Pathname.new("source/assets/docs.md")
65
+ ]
66
+
67
+ files.each_with_index do |file, i|
68
+ create_markdown_path(file, "# Page #{i + 1}")
69
+ end
70
+
71
+ config = Mint::Config.with_defaults(
72
+ working_directory: Pathname.new("source"),
73
+ destination_directory: Pathname.new("../build"), # Relative to root directory
74
+ preserve_structure: true
75
+ )
76
+
77
+ Mint::Commandline.publish!(files, config: config)
78
+
79
+ # Should strip 'source/' prefix due to root directory
80
+ expect(File.exist?("build/pages/home.html")).to be true
81
+ expect(File.exist?("build/pages/about.html")).to be true
82
+ expect(File.exist?("build/assets/docs.html")).to be true
83
+
84
+ # Should not have source/ prefix
85
+ expect(File.exist?("build/source/pages/home.html")).to be false
86
+ end
87
+ end
88
+
89
+ describe "style file placement with paths" do
90
+ it "creates style files in correct destination with external mode" do
91
+ FileUtils.mkdir_p(["content", "public"])
92
+ create_markdown_path("content/article.md", "# Article")
93
+
94
+ config = Mint::Config.with_defaults(
95
+ destination_directory: Pathname.new("public"),
96
+ style_mode: :external,
97
+ preserve_structure: true
98
+ )
99
+
100
+ Mint::Commandline.publish!([Pathname.new("content/article.md")], config: config)
101
+
102
+ expect(File.exist?("public/content/article.html")).to be true
103
+ expect(File.exist?("public/style.css")).to be true
104
+ end
105
+
106
+ it "handles style destination directory with nested sources" do
107
+ FileUtils.mkdir_p(["src/docs", "web/pages", "web/assets"])
108
+ create_markdown_path("src/docs/guide.md", "# Guide")
109
+
110
+ config = Mint::Config.with_defaults(
111
+ destination_directory: Pathname.new("web/pages"),
112
+ style_destination_directory: Pathname.new("web/assets"),
113
+ style_mode: :external,
114
+ preserve_structure: true
115
+ )
116
+
117
+ Mint::Commandline.publish!([Pathname.new("src/docs/guide.md")], config: config)
118
+
119
+ expect(File.exist?("web/pages/src/docs/guide.html")).to be true
120
+ expect(File.exist?("web/pages/web/assets/style.css")).to be true
121
+ end
122
+ end
123
+
124
+ describe "error handling with paths" do
125
+ it "handles nonexistent source files gracefully" do
126
+ config = Mint::Config.with_defaults(destination_directory: Pathname.new("output"), preserve_structure: true)
127
+
128
+ expect {
129
+ Mint::Commandline.publish!([Pathname.new("nonexistent/file.md")], config: config)
130
+ }.to raise_error(Errno::ENOENT)
131
+ end
132
+
133
+ it "creates deeply nested destination directories as needed" do
134
+ create_markdown_path("test.md", "# Test")
135
+
136
+ config = Mint::Config.with_defaults(
137
+ destination_directory: Pathname.new("very/deeply/nested/output/directory")
138
+ )
139
+
140
+ expect {
141
+ Mint::Commandline.publish!([Pathname.new("test.md")], config: config)
142
+ }.not_to raise_error
143
+
144
+ expect(File.exist?("very/deeply/nested/output/directory/test.html")).to be true
145
+ end
146
+ end
147
+
148
+ describe "cross-linking with preserved paths" do
149
+ it "transforms markdown links correctly with nested paths" do
150
+ FileUtils.mkdir_p(["docs/guides", "docs/api", "site"])
151
+
152
+ # Create files with cross-references
153
+ create_markdown_path("docs/guides/intro.md",
154
+ "# Introduction\n\nSee also [API Reference](../api/reference.md).")
155
+ create_markdown_path("docs/api/reference.md",
156
+ "# API Reference\n\nBack to [Introduction](../guides/intro.md).")
157
+
158
+ files = [Pathname.new("docs/guides/intro.md"), Pathname.new("docs/api/reference.md")]
159
+ config = Mint::Config.with_defaults(destination_directory: Pathname.new("site"), preserve_structure: true)
160
+
161
+ Mint::Commandline.publish!(files, config: config)
162
+
163
+ # Check that links were transformed
164
+ intro_content = File.read("site/guides/intro.html")
165
+ expect(intro_content).to include("../api/reference.html")
166
+
167
+ api_content = File.read("site/api/reference.html")
168
+ expect(api_content).to include("../guides/intro.html")
169
+ end
170
+ end
171
+
172
+ describe "real-world scenarios" do
173
+ it "handles documentation site structure" do
174
+ # Simulate hugo/jekyll-style structure
175
+ FileUtils.mkdir_p([
176
+ "content/posts/2023",
177
+ "content/docs/v1.0",
178
+ "content/about",
179
+ "public"
180
+ ])
181
+
182
+ files = [
183
+ Pathname.new("content/posts/2023/welcome.md"),
184
+ Pathname.new("content/docs/v1.0/getting-started.md"),
185
+ Pathname.new("content/docs/v1.0/api.md"),
186
+ Pathname.new("content/about/index.md")
187
+ ]
188
+
189
+ files.each_with_index do |file, i|
190
+ create_markdown_path(file, "# Content #{i + 1}")
191
+ end
192
+
193
+ config = Mint::Config.with_defaults(destination_directory: Pathname.new("public"), preserve_structure: true)
194
+ Mint::Commandline.publish!(files, config: config)
195
+
196
+ expect(File.exist?("public/posts/2023/welcome.html")).to be true
197
+ expect(File.exist?("public/docs/v1.0/getting-started.html")).to be true
198
+ expect(File.exist?("public/docs/v1.0/api.html")).to be true
199
+ expect(File.exist?("public/about/index.html")).to be true
200
+ end
201
+
202
+ it "handles monorepo documentation structure" do
203
+ # Simulate monorepo with multiple packages
204
+ FileUtils.mkdir_p([
205
+ "packages/core/docs",
206
+ "packages/ui/docs",
207
+ "packages/utils/docs",
208
+ "docs-site"
209
+ ])
210
+
211
+ files = [
212
+ Pathname.new("packages/core/docs/api.md"),
213
+ Pathname.new("packages/ui/docs/components.md"),
214
+ Pathname.new("packages/utils/docs/helpers.md")
215
+ ]
216
+
217
+ files.each_with_index do |file, i|
218
+ create_markdown_path(file, "# Package Documentation #{i + 1}")
219
+ end
220
+
221
+ config = Mint::Config.with_defaults(destination_directory: Pathname.new("docs-site"), preserve_structure: true)
222
+ Mint::Commandline.publish!(files, config: config)
223
+
224
+ expect(File.exist?("docs-site/core/docs/api.html")).to be true
225
+ expect(File.exist?("docs-site/ui/docs/components.html")).to be true
226
+ expect(File.exist?("docs-site/utils/docs/helpers.html")).to be true
227
+ end
228
+ end
229
+ end
230
+ end