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
@@ -0,0 +1,171 @@
1
+ require "pathname"
2
+ require "fileutils"
3
+
4
+ require_relative "./document"
5
+ require_relative "./helpers"
6
+ require_relative "./css_parser"
7
+
8
+ module Mint
9
+ class Workspace
10
+ def initialize(markdown_paths, config)
11
+ @config = config
12
+ @documents = []
13
+
14
+ # 1. Create destination_html_paths, mapped 1:1 with markdown_paths,
15
+ # and autodropping any directories that are common to all files,
16
+ # if config.autodrop is on.
17
+ # 2. Zip markdown_paths and destination_html_paths together so they
18
+ # are paired
19
+ # 3. For each pair, create a document with the source and destination
20
+ # paths, and create navigation tree JSON that's relative to
21
+ # the specific document at hand
22
+ #
23
+ # NOTE: All directories at this stage are relative so that they can be
24
+ # concatenated and manipulated. The working directory is passed into
25
+ # the Document, which is where it's used to calculate its actual
26
+ # absolute destination.
27
+
28
+ autodrop_levels = calculate_autodrop_levels_for(markdown_paths)
29
+ style_path = find_style_path(@config.style_name)
30
+ layout_path = find_layout_path(@config.layout_name)
31
+ style_destination_path = @config.destination_directory + @config.style_destination_directory
32
+
33
+ markdown_paths.each_with_index do |path, index|
34
+ destination_path = destination_path_for(path,
35
+ autodrop_levels: autodrop_levels,
36
+ preserve_structure: @config.preserve_structure,
37
+ output_file_format: @config.output_file_format)
38
+
39
+ @documents << Document.new(
40
+ working_directory: @config.working_directory,
41
+ source_path: path,
42
+ destination_path: destination_path,
43
+ destination_directory_path: @config.destination_directory,
44
+ layout_path: layout_path,
45
+ style_path: style_path,
46
+ style_destination_path: style_destination_path,
47
+ style_mode: @config.style_mode,
48
+ insert_title_heading: @config.insert_title_heading,
49
+ transform_links: lambda {|link_basename| update_basename(link_basename, new_extension: "html", format_string: @config.output_file_format) },
50
+ render_style: index == 0
51
+ )
52
+ end
53
+ end
54
+
55
+ def publish!
56
+ if @config.navigation
57
+ @documents.map do |document|
58
+ document.publish!(show_navigation: true, navigation: @documents, navigation_depth: @config.navigation_depth, navigation_title: @config.navigation_title)
59
+ end
60
+ else
61
+ @documents.map do |document|
62
+ document.publish!(show_navigation: false, navigation: nil, navigation_depth: 0, navigation_title: nil)
63
+ end
64
+ end
65
+ end
66
+
67
+ # Returns the style path relative to the working directory
68
+ #
69
+ # @param [String] style_name name of the style to find
70
+ # @return [Pathname] the style path relative to the working directory
71
+ def find_style_path(style_name)
72
+ style_source = Style.find_by_name(style_name)
73
+ raise StyleNotFoundException, "Style '#{style_name}' does not exist." unless style_source
74
+
75
+ if style_source.absolute?
76
+ style_source.relative_path_from(@config.working_directory)
77
+ else
78
+ style_source
79
+ end
80
+ end
81
+
82
+ # Returns the layout path relative to the working directory
83
+ #
84
+ # @param [String] layout_name name of the layout to find
85
+ # @return [Pathname] the layout path relative to the working directory
86
+ def find_layout_path(layout_name)
87
+ layout_source = Layout.find_by_name(layout_name) ||
88
+ Layout.find_by_name(Config::DEFAULT_LAYOUT_NAME)
89
+ raise LayoutNotFoundException, "Layout '#{layout_name}' does not exist." unless layout_source
90
+
91
+ if layout_source.absolute?
92
+ layout_source.relative_path_from(@config.working_directory)
93
+ else
94
+ layout_source
95
+ end
96
+ end
97
+
98
+ # Updates the basename of a filename with a new extension and format string
99
+ #
100
+ # @param [String] filename the filename to update
101
+ # @param [String] new_extension the new extension to use
102
+ # @param [String] format_string the format string to use
103
+ # @return [String] the updated filename
104
+ def update_basename(filename, new_extension:, format_string:)
105
+ filename_no_ext = File.basename(filename, ".*")
106
+ format_string % {
107
+ name: filename_no_ext,
108
+ ext: new_extension,
109
+ original_ext: File.extname(filename)[1..-1]
110
+ }
111
+ end
112
+
113
+ # Updates the basename of a path with a new extension and format string
114
+ #
115
+ # @param [Pathname] path the path to update
116
+ # @param [String] new_extension the new extension to use
117
+ # @param [String] format_string the format string to use
118
+ # @return [Pathname] the updated path
119
+ def update_path_basename(path, new_extension:, format_string:)
120
+ path.sub(path.basename.to_s, update_basename(path.basename, new_extension: new_extension, format_string: format_string))
121
+ end
122
+
123
+ # Calculates the number of levels to "autodrop" from the paths. Autodropping is dropping
124
+ # any parent directories that are common to all paths. This makes it easy for users to pass
125
+ # in directories not in the current working directory and have them automatically removed
126
+ # from the final output paths. Autodropping is only done if @config.autodrop is true.
127
+ #
128
+ # @param [Array<Pathname>] markdown_paths the paths to calculate the autodrop levels for
129
+ # @return [Integer] the number of levels to drop
130
+ def calculate_autodrop_levels_for(markdown_paths)
131
+ return 0 unless @config.autodrop
132
+ return 0 if markdown_paths.length <= 1
133
+
134
+ # Find common parent directories by splitting paths and finding common prefix
135
+ path_parts = markdown_paths.map {|path| path.to_s.split('/').reject(&:empty?) }
136
+ return 0 if path_parts.empty?
137
+
138
+ # Find the minimum length to avoid index errors
139
+ min_length = path_parts.map(&:length).min
140
+ return 0 if min_length == 0
141
+
142
+ # Find common prefix length
143
+ common_prefix_length = 0
144
+ (0...min_length).each do |i|
145
+ if path_parts.all? {|parts| parts[i] == path_parts.first[i] }
146
+ common_prefix_length = i + 1
147
+ else
148
+ break
149
+ end
150
+ end
151
+
152
+ # Only drop if there's a meaningful common prefix and it leaves at least one level
153
+ if common_prefix_length > 0 && path_parts.any? {|parts| parts.length > common_prefix_length }
154
+ common_prefix_length
155
+ else
156
+ 0
157
+ end
158
+ end
159
+
160
+ def destination_path_for(path, autodrop_levels:, preserve_structure:, output_file_format:)
161
+ if preserve_structure
162
+ # Keep directory structure, but apply autodrop if enabled and convert extension to HTML
163
+ dropped_path = Helpers.drop_pathname(path, autodrop_levels)
164
+ update_path_basename(dropped_path, new_extension: "html", format_string: output_file_format)
165
+ else
166
+ # Flatten all files directly into destination directory (no subdirectories)
167
+ Pathname.new(update_basename(path.basename, new_extension: "html", format_string: output_file_format))
168
+ end
169
+ end
170
+ end
171
+ end
data/lib/mint.rb CHANGED
@@ -1,12 +1,44 @@
1
- require "mint/helpers"
2
- require "mint/mint"
3
- require "mint/resource"
4
- require "mint/layout"
5
- require "mint/style"
6
- require "mint/document"
7
- require "mint/version"
8
- require "mint/css"
9
- require "mint/command_line"
10
- require "mint/exceptions"
11
- require "mint/plugin"
12
- require "mint/css_template"
1
+ require "pathname"
2
+ require "fileutils"
3
+ require "yaml"
4
+ require "active_support/core_ext/string/output_safety"
5
+
6
+ require_relative "mint/version"
7
+ require_relative "mint/commandline/run"
8
+ require_relative "mint/commandline/parse"
9
+ require_relative "mint/commandline/publish"
10
+ require_relative "mint/css_dsl"
11
+ require_relative "mint/css_parser"
12
+ require_relative "mint/config"
13
+ require_relative "mint/exceptions"
14
+ require_relative "mint/renderers/css_renderer"
15
+ require_relative "mint/renderers/markdown_renderer"
16
+ require_relative "mint/renderers/erb_renderer"
17
+ require_relative "mint/document"
18
+ require_relative "mint/workspace"
19
+ require_relative "mint/layout"
20
+ require_relative "mint/style"
21
+ require_relative "mint/template"
22
+
23
+ module Mint
24
+ PROJECT_ROOT = (Pathname.new(__FILE__).realpath.dirname + "..").to_s
25
+ LOCAL_SCOPE = Pathname.new(".mint")
26
+ USER_SCOPE = Pathname.new("~/.config/mint").expand_path
27
+ GLOBAL_SCOPE = Pathname.new("#{PROJECT_ROOT}/config").expand_path
28
+ PATH = [LOCAL_SCOPE, USER_SCOPE, GLOBAL_SCOPE]
29
+ CONFIG_FILE = "config.toml"
30
+ TEMPLATES_DIRECTORY = "templates"
31
+
32
+ # Returns a hash of all active config, merging global, user, and local
33
+ # scoped config. Local overrides user, which overrides global config.
34
+ #
35
+ # @return [Config] a structured set of configuration options
36
+ def self.configuration
37
+ Mint::PATH.
38
+ reverse.
39
+ map {|p| p + Mint::CONFIG_FILE }.
40
+ select(&:exist?).
41
+ map {|p| Config.load_file p }.
42
+ reduce(Config.defaults) {|agg, cfg| agg.merge cfg }
43
+ end
44
+ end
data/man/mint.1 CHANGED
@@ -15,10 +15,13 @@ Mint processes Markdown, Textile, and other templating languages into styled HTM
15
15
  Transform one or more source files into HTML documents
16
16
  .SH OPTIONS
17
17
  .TP
18
+ .BR \-h ", " \-\-help
19
+ Show mint usage information
20
+ .TP
18
21
  .BR \-d ", " \-\-destination " " \fIDIRECTORY\fR
19
22
  Specify a destination directory, relative to the root
20
23
  .TP
21
- .BR \-\-style\-mode " " \fIMODE\fR
24
+ .BR \-m ", " \-\-style\-mode " " \fIMODE\fR
22
25
  Specify how styles are included (inline, external, original). Default is inline.
23
26
  .TP
24
27
  .BR \-\-style\-destination " " \fIDESTINATION\fR
@@ -28,74 +31,124 @@ Create stylesheet at specified directory or file path and link it. This sets sty
28
31
  Specify a template to use for both layout and styling
29
32
  .TP
30
33
  .BR \-l ", " \-\-layout " " \fILAYOUT\fR
31
- Specify a specific layout template
34
+ Specify a specific layout template by name
32
35
  .TP
33
36
  .BR \-\-style " " \fISTYLE\fR
34
- Specify a specific style template
37
+ Specify a specific style template by name
35
38
  .TP
36
- .BR \-g ", " \-\-global
37
- Specify config changes on a global level
39
+ .BR \-w ", " \-\-working\-dir " " \fIWORKING_DIR\fR
40
+ Specify a working directory outside the current directory
38
41
  .TP
39
- .BR \-u ", " \-\-user
40
- Specify config changes on a user-wide level
42
+ .BR \-o ", " \-\-output\-file " " \fIFORMAT\fR
43
+ Specify output filename format with substitutions (%{basename}, %{original_ext}, %{new_extension})
41
44
  .TP
42
- .BR \-\-local
43
- Specify config changes on a local level (default)
45
+ .BR \-\-preserve\-structure
46
+ Preserve source directory structure (e.g., nesting) in destination (default: true)
44
47
  .TP
45
- .BR \-r ", " \-\-recursive
46
- Recursively find all Markdown files in subdirectories
48
+ .BR \-\-no\-preserve\-structure
49
+ Flatten all files into destination directory
47
50
  .TP
48
- .BR \-v ", " \-\-verbose
49
- Enable verbose output
51
+ .BR \-\-navigation
52
+ Enable navigation panel showing all files
50
53
  .TP
51
- .BR \-h ", " \-\-help
52
- Display help information
54
+ .BR \-\-no\-navigation
55
+ Disable navigation panel
56
+ .TP
57
+ .BR \-\-navigation\-title " " \fITITLE\fR
58
+ Set title for navigation panel
59
+ .TP
60
+ .BR \-\-autodrop
61
+ Automatically drop common directory levels from output paths and navigation (default: true)
62
+ .TP
63
+ .BR \-\-no\-autodrop
64
+ Don't automatically drop common directory levels
65
+ .TP
66
+ .BR \-\-navigation\-depth " " \fIDEPTH\fR
67
+ Maximum depth to show in navigation (default: 3)
68
+ .TP
69
+ .BR \-\-insert\-title\-heading
70
+ Insert document title as H1 heading into content
71
+ .TP
72
+ .BR \-\-no\-insert\-title\-heading
73
+ Don't insert title as H1 heading
53
74
  .SH STYLE OPTIONS
54
75
  Mint offers flexible control over how stylesheets are incorporated into your documents:
55
76
 
56
- .SS Inline Styles (Default)
77
+ .SS Inline styles (Default)
57
78
  By default, Mint inlines CSS directly into your HTML documents, creating self-contained files:
58
79
  .RS
59
80
  .nf
60
- mint publish document.md
81
+ mint publish Document.md
61
82
  .fi
62
83
  .RE
63
84
 
64
- .SS External Stylesheets
85
+ .SS External stylesheets
65
86
  Create external stylesheets that are linked from your HTML documents:
66
87
  .RS
67
88
  .nf
68
- mint publish document.md --style-destination css
69
- mint publish document.md --style-destination styles/main.css
89
+ mint publish Document.md --style-destination css
90
+ mint publish Document.md --style-destination styles/main.css
70
91
  .fi
71
92
  .RE
72
93
 
73
94
  External stylesheets are useful when you want to share stylesheets across multiple documents, keep HTML files smaller, or allow separate caching of styles.
95
+
96
+ .SH DIRECTORY STRUCTURE
97
+ Mint provides flexible control over how source directory structure is handled in the output:
98
+
99
+ By default, Mint preserves the source directory structure but applies "autodrop" to remove common directory levels. For example, if all files are under docs/content/, that common prefix is automatically dropped.
100
+
101
+ Use --no-preserve-structure to flatten all files into the destination directory, ignoring source directory structure entirely.
102
+
103
+ Use --no-autodrop with --preserve-structure to keep the complete original directory structure without dropping any levels.
104
+ .SH CONFIGURATION
105
+ Mint can be configured using TOML configuration files in the following order of precedence:
106
+ .IP 1. 2
107
+ Command-line arguments (highest priority)
108
+ .IP 2. 2
109
+ Local config file: .mint/config.toml
110
+ .IP 3. 2
111
+ User config file: ~/.config/mint/config.toml
112
+ .IP 4. 2
113
+ Built-in defaults (lowest priority)
114
+
115
+ Boolean options set to true in configuration files can be overridden using --no- flags:
116
+ .RS
117
+ .nf
118
+ # If config.toml has: navigation = true
119
+ mint publish Document.md --no-navigation
120
+ .fi
121
+ .RE
74
122
  .SH EXAMPLES
75
123
  .TP
76
124
  Transform a single Markdown file:
77
125
  .nf
78
- mint publish document.md
126
+ mint publish Document.md
79
127
  .fi
80
128
  .TP
81
129
  Transform multiple files:
82
130
  .nf
83
- mint publish doc1.md doc2.md doc3.md
131
+ mint publish Document1.md Document2.md Document3.md
132
+ .fi
133
+ .TP
134
+ Insert title as H1 heading:
135
+ .nf
136
+ mint publish Document.md --insert-title-heading
84
137
  .fi
85
138
  .TP
86
139
  Use a specific template:
87
140
  .nf
88
- mint publish resume.md --template resume
141
+ mint publish Document.md --template nord
89
142
  .fi
90
143
  .TP
91
144
  Create external stylesheet:
92
145
  .nf
93
- mint publish document.md --style-destination css
146
+ mint publish Document.md --style-destination css
94
147
  .fi
95
148
  .TP
96
- Recursively process all Markdown files:
149
+ Override boolean config file settings with --no-* variants:
97
150
  .nf
98
- mint publish --recursive
151
+ mint publish Document.md --no-navigation --no-insert-title-heading
99
152
  .fi
100
153
  .SH TEMPLATES
101
154
  Mint comes with several built-in templates:
@@ -103,32 +156,20 @@ Mint comes with several built-in templates:
103
156
  .B default
104
157
  \- Clean, professional styling
105
158
  .IP \(bu 2
106
- .B zen
107
- \- Minimalist design
108
- .IP \(bu 2
109
- .B protocol
110
- \- Technical documentation style
111
- .IP \(bu 2
112
- .B newspaper
113
- \- Multi-column layout
159
+ .B basic
160
+ \- Minimalist design focused on the text
114
161
  .IP \(bu 2
115
162
  .B nord/nord-dark
116
- \- Modern color schemes
163
+ \- Modern color schemes using the Nord color scheme
117
164
  .PP
118
- Templates can be written in any format accepted by the Tilt template interface library (ERB, Haml, etc.).
165
+ Templates use ERB-flavored HTML for layouts and CSS for styling.
119
166
  .SH FILES
120
167
  .TP
121
168
  .I ~/.config/mint/
122
- User-specific configuration and templates
169
+ User-level configuration and templates ('user' scope)
123
170
  .TP
124
171
  .I .mint/
125
- Project-specific configuration and templates
126
- .TP
127
- .I config.yaml
128
- Configuration file (can exist at global, user, or local levels)
129
- .SH SEE ALSO
130
- .BR markdown (1),
131
- .BR tilt (1)
172
+ Project-level configuration and templates ('local' scope)
132
173
  .SH AUTHOR
133
174
  David Jacobs <david@wit.io>
134
175
  .SH HOMEPAGE
data/spec/cli/README.md CHANGED
@@ -60,11 +60,11 @@ end
60
60
 
61
61
  # Output capture
62
62
  stdout, stderr = capture_output do
63
- Mint::CommandLine.some_method
63
+ Mint::Commandline.some_method
64
64
  end
65
65
 
66
66
  # File creation
67
- create_markdown_file("test.md", "# Content")
67
+ create_markdown_path("test.md", "# Content")
68
68
  create_template_directory("custom", with_layout: true)
69
69
 
70
70
  # Command execution