mdtoc 0.1.5 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f092d7c28f783773c0c48be2f48ec708b986cb2bc059a5312420a15dd7e57878
4
- data.tar.gz: c1af35b25f4c5c9596c232572b158074574ba16b154c72de1ad84c22d189ec40
3
+ metadata.gz: 2c01cef42824ceeae479dc235cbe2c7565c2d6ef045074c8d55b34a821ee719d
4
+ data.tar.gz: c25c67f2bf841dd9e1e3bb6a632035693299e7a53367b5dd255ecfbc125adab2
5
5
  SHA512:
6
- metadata.gz: 0f20e8dbf0ce1d8ccc67ede27cdb15c8a6253d01e35c44780194b8322ccd3281e8f5c9fb8a3d311fcd4f91236988e1379cb639315711f87549f6dbd4fed44402
7
- data.tar.gz: fa16fbf938973290b2724a8d1215aca328260813592083f2ea7adf9a6503c1d981702594260ab38969de05b13e78477e60ad56e201f1b7e754aa9759666899f8
6
+ metadata.gz: 603bec1ab105a7438bb2d0c2e4fb0c7eead9c63b57bfe33ca9354b05458d435805ce614cd11549527749092f2cffdc1289691a177b3c86161bac714f877c3eb7
7
+ data.tar.gz: 6bb0b63c4217f899d2277ba35baf7966cd97219e88f111c7a842b535108c698ac0260c0cc1f2c7e24858c9464a9cac333ea1fa4a7244104b051ba3184ed326bd
data/bin/mdtoc CHANGED
@@ -2,5 +2,5 @@
2
2
  # typed: true
3
3
  # frozen_string_literal: true
4
4
 
5
- require 'mdtoc'
5
+ require "mdtoc"
6
6
  Mdtoc.main(ARGV)
data/lib/mdtoc/cli.rb CHANGED
@@ -19,7 +19,7 @@ module Mdtoc
19
19
  exit
20
20
  end
21
21
  parser_.on('-o', '--output PATH', 'Update a table of contents in the file at PATH')
22
- parser_.on('-a', '--[no-]append', 'Append to the --output file if a <!-- mdtoc --> tag isn\'t found')
22
+ parser_.on('-a', '--[no-]append', "Append to the --output file if a <!-- mdtoc --> tag isn't found")
23
23
  parser_.on('-c', '--[no-]create', 'Create the --output file if it does not exist')
24
24
  end
25
25
 
@@ -0,0 +1,50 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'sorbet-runtime'
5
+
6
+ module Mdtoc
7
+ module Markdown
8
+ module FragmentGenerator
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ interface!
13
+
14
+ sig { abstract.params(label: String).returns(String) }
15
+ def generate(label); end
16
+
17
+ class GitHub
18
+ extend T::Sig
19
+ include FragmentGenerator
20
+
21
+ sig { void }
22
+ def initialize
23
+ @counts = T.let(Hash.new(0), T::Hash[String, Integer])
24
+ end
25
+
26
+ sig { override.params(label: String).returns(String) }
27
+ def generate(label)
28
+ # GitHub's fragment generation:
29
+ # 1. Downcase
30
+ # 2. Replace spaces with dashes
31
+ # 3. Remove non-alphanumeric characters (keeping dashes, dots and underscores)
32
+ # 4. Collapse multiple dashes
33
+ # 5. Remove leading/trailing dashes and dots (common in many implementations)
34
+ fragment = label.downcase.tr(' ', '-').gsub(/[^\w.-]/, '')
35
+ fragment = fragment.gsub(/-+/, '-')
36
+ fragment = fragment.gsub(/^[.-]+|[.-]+$/, '')
37
+
38
+ count = @counts[fragment]
39
+ @counts[fragment] += 1
40
+
41
+ if count.positive?
42
+ "#{fragment}-#{count}"
43
+ else
44
+ fragment
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'sorbet-runtime'
5
+ require_relative 'fragment_generator'
5
6
 
6
7
  module Mdtoc
7
8
  module Markdown
@@ -10,9 +11,8 @@ module Mdtoc
10
11
 
11
12
  sig { params(depth: Integer, label: String, url: String).void }
12
13
  def initialize(depth, label, url)
13
- if depth < 0
14
- raise ArgumentError, "Header depth must be >= 0, but was #{depth}"
15
- end
14
+ raise ArgumentError, "Header depth must be >= 0, but was #{depth}" if depth.negative?
15
+
16
16
  @depth = depth
17
17
  @label = normalize_label(label)
18
18
  @url = url
@@ -33,15 +33,22 @@ module Mdtoc
33
33
 
34
34
  def normalize_label(label)
35
35
  label = label.strip.tr("\t\n\r", '') # Remove whitespace characters other than spaces.
36
- label.gsub(/\[(.*)\]\(.*\)/, '\1') # Remove links
36
+ label.gsub(/\[(.*?)\]\(.*?\)/, '\1') # Remove links
37
37
  end
38
38
  end
39
39
 
40
40
  class HeaderWithFragment < Header
41
- sig { params(depth: Integer, label: String, url: String).void }
42
- def initialize(depth, label, url)
43
- super
44
- @url += "##{@label.downcase.tr(' ', '-').gsub(/[^\w\-]/, '')}"
41
+ sig do
42
+ params(
43
+ depth: Integer,
44
+ label: String,
45
+ url: String,
46
+ generator: FragmentGenerator
47
+ ).void
48
+ end
49
+ def initialize(depth, label, url, generator:)
50
+ super(depth, label, url)
51
+ @url += "##{generator.generate(@label)}"
45
52
  end
46
53
  end
47
54
  end
@@ -3,43 +3,102 @@
3
3
 
4
4
  require 'sorbet-runtime'
5
5
  require_relative 'header'
6
+ require_relative 'fragment_generator'
6
7
 
7
8
  module Mdtoc
8
9
  module Markdown
9
10
  class Parser
10
11
  extend T::Sig
11
12
 
12
- sig { params(depth: Integer, url: String).void }
13
- def initialize(depth, url)
13
+ sig do
14
+ params(
15
+ depth: Integer,
16
+ url: String,
17
+ generator: FragmentGenerator
18
+ ).void
19
+ end
20
+ def initialize(depth, url, generator: FragmentGenerator::GitHub.new)
14
21
  @depth = depth
15
22
  @url = url
23
+ @generator = generator
24
+ @in_code_block = T.let(false, T::Boolean)
25
+ @in_html_comment = T.let(false, T::Boolean)
16
26
  end
17
27
 
18
28
  sig { params(lines: T::Enumerable[String]).returns(T::Array[Header]) }
19
29
  def headers(lines)
20
- # TODO: Skip headers within multi-line comments.
21
- # TODO: Handle --- and === style headers.
22
- skip = T.let(false, T::Boolean)
23
- lines.filter_map do |line|
24
- # Skip code blocks.
25
- if line.start_with?('```') && !T.must(line[3..]).strip.end_with?('```')
26
- skip = !skip
30
+ @in_code_block = false
31
+ @in_html_comment = false
32
+
33
+ headers = T.let([], T::Array[Header])
34
+ prev_line = T.let(nil, T.nilable(String))
35
+
36
+ lines.each do |line|
37
+ stripped = line.strip
38
+
39
+ if skip_line?(line, stripped)
40
+ prev_line = line
41
+ next
42
+ end
43
+
44
+ if line.start_with?('#')
45
+ headers << header(line)
46
+ elsif (h = process_setext_header(stripped, prev_line))
47
+ headers << h
27
48
  end
28
- next if skip || !line.start_with?('#')
29
49
 
30
- header(line)
50
+ prev_line = line
31
51
  end
52
+
53
+ headers
32
54
  end
33
55
 
34
56
  private
35
57
 
58
+ sig { params(line: String, stripped: String).returns(T::Boolean) }
59
+ def skip_line?(line, stripped)
60
+ html_comment?(stripped) || code_block?(line)
61
+ end
62
+
63
+ sig { params(stripped: String).returns(T::Boolean) }
64
+ def html_comment?(stripped)
65
+ if stripped.start_with?('<!--')
66
+ @in_html_comment = true unless stripped.end_with?('-->')
67
+ return true
68
+ elsif @in_html_comment && stripped.end_with?('-->')
69
+ @in_html_comment = false
70
+ return true
71
+ end
72
+ @in_html_comment
73
+ end
74
+
75
+ sig { params(line: String).returns(T::Boolean) }
76
+ def code_block?(line)
77
+ if line.start_with?('```') && !T.must(line[3..]).strip.end_with?('```')
78
+ @in_code_block = !@in_code_block
79
+ return true
80
+ end
81
+ @in_code_block
82
+ end
83
+
84
+ sig { params(stripped: String, prev_line: T.nilable(String)).returns(T.nilable(Header)) }
85
+ def process_setext_header(stripped, prev_line)
86
+ return nil unless prev_line && !prev_line.strip.empty?
87
+
88
+ if stripped.match?(/^=+$/)
89
+ HeaderWithFragment.new(@depth, prev_line.strip, @url, generator: @generator)
90
+ elsif stripped.match?(/^-+$/)
91
+ HeaderWithFragment.new(@depth + 1, prev_line.strip, @url, generator: @generator)
92
+ end
93
+ end
94
+
36
95
  sig { params(line: String).returns(HeaderWithFragment) }
37
96
  def header(line)
38
97
  m = T.must(line.strip.match(/^(#+)\s*(.*)$/))
39
98
  num_hashes = m[1]&.count('#') || 1
40
99
  depth = @depth + num_hashes - 1
41
100
  label = m[2] || ''
42
- HeaderWithFragment.new(depth, label, @url)
101
+ HeaderWithFragment.new(depth, label, @url, generator: @generator)
43
102
  end
44
103
  end
45
104
  end
data/lib/mdtoc/node.rb CHANGED
@@ -10,6 +10,7 @@ module Mdtoc
10
10
  class Node
11
11
  extend T::Helpers
12
12
  extend T::Sig
13
+
13
14
  abstract!
14
15
 
15
16
  class << self
@@ -18,10 +19,9 @@ module Mdtoc
18
19
  sig { params(path: String, depth: Integer).returns(Node) }
19
20
  def for_path(path, depth = 0)
20
21
  # Ensure that `path` is a relative path, so that all links are relative and therefore portable.
21
- path = Pathname.new(path)
22
- path = path.relative_path_from(Dir.pwd) if path.absolute?
23
- path = path.to_s
24
- File.directory?(path) ? DirNode.new(path, depth) : FileNode.new(path, depth)
22
+ pathname = Pathname.new(path)
23
+ pathname = pathname.relative_path_from(Dir.pwd) if pathname.absolute?
24
+ pathname.directory? ? DirNode.new(pathname, depth) : FileNode.new(pathname, depth)
25
25
  end
26
26
 
27
27
  sig { params(paths: T::Array[String]).returns(String) }
@@ -32,7 +32,7 @@ module Mdtoc
32
32
  end
33
33
  end
34
34
 
35
- sig { params(path: String, depth: Integer).void }
35
+ sig { params(path: Pathname, depth: Integer).void }
36
36
  def initialize(path, depth)
37
37
  @path = path
38
38
  @depth = depth
@@ -43,22 +43,30 @@ module Mdtoc
43
43
 
44
44
  sig { returns(String) }
45
45
  def label
46
- File.basename(@path, File.extname(@path)).gsub(/_+/, ' ').gsub(/\s+/, ' ').capitalize
46
+ @path.basename(@path.extname).to_s.gsub(/_+/, ' ').gsub(/\s+/, ' ').capitalize
47
47
  end
48
48
 
49
49
  class DirNode < Node
50
50
  sig { override.returns(T::Array[Mdtoc::Markdown::Header]) }
51
51
  def headers
52
- readme_path = T.let(nil, T.nilable(String))
53
- child_headers = Dir
54
- .each_child(@path)
55
- .reject { |path| readme_path = File.join(@path, path) if path.casecmp?('readme.md') }
56
- .sort!
57
- .flat_map { |path| Node.for_path(File.join(@path, path), @depth + 1).headers }
52
+ readme_path = T.let(nil, T.nilable(Pathname))
53
+ children = @path.children.reject do |child|
54
+ if child.basename.to_s.casecmp?('readme.md')
55
+ readme_path = child
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ child_headers = children.sort.flat_map do |child|
63
+ Node.for_path(child.to_s, @depth + 1).headers
64
+ end
65
+
58
66
  return child_headers unless readme_path
59
67
 
60
68
  # Include the headers from the README at the beginning.
61
- readme_headers = FileNode.new(readme_path, @depth).headers
69
+ readme_headers = FileNode.new(T.must(readme_path), @depth).headers
62
70
  readme_headers + child_headers
63
71
  end
64
72
  end
@@ -66,11 +74,12 @@ module Mdtoc
66
74
  class FileNode < Node
67
75
  sig { override.returns(T::Array[Mdtoc::Markdown::Header]) }
68
76
  def headers
69
- parser = Markdown::Parser.new(@depth, @path)
70
- headers = parser.headers(File.foreach(@path))
77
+ path_s = @path.to_s
78
+ parser = Markdown::Parser.new(@depth, path_s)
79
+ headers = parser.headers(@path.each_line)
71
80
  return headers if headers[0]&.top_level?(@depth)
72
81
 
73
- headers.unshift(Mdtoc::Markdown::Header.new(@depth, label, @path))
82
+ headers.unshift(Mdtoc::Markdown::Header.new(@depth, label, path_s))
74
83
  end
75
84
  end
76
85
  end
data/lib/mdtoc/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Mdtoc
5
- VERSION = '0.1.5'
5
+ VERSION = '0.3.0'
6
6
  end
data/lib/mdtoc/writer.rb CHANGED
@@ -1,6 +1,9 @@
1
- # typed: strict
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'fileutils'
5
+ require 'tempfile'
6
+
4
7
  module Mdtoc
5
8
  module Writer
6
9
  COMMENT_BEGIN = '<!-- mdtoc -->'
@@ -13,8 +16,15 @@ module Mdtoc
13
16
  def write(toc, path, append, create)
14
17
  validate_path(path, create)
15
18
  new_content = content(toc, path, append)
16
- File.open(path, 'w') do |f|
17
- f.write(new_content)
19
+
20
+ # Write to a temporary file and rename it to the target path to ensure atomic writing.
21
+ temp = Tempfile.new(File.basename(path), File.dirname(path))
22
+ begin
23
+ temp.write(new_content)
24
+ temp.close
25
+ FileUtils.mv(temp.path, path)
26
+ ensure
27
+ temp.close!
18
28
  end
19
29
  end
20
30
 
@@ -25,17 +35,12 @@ module Mdtoc
25
35
  toc = "#{COMMENT_BEGIN}\n#{toc}\n#{COMMENT_END}"
26
36
 
27
37
  begin
28
- f = File.open(path)
29
- rescue
30
- # If File.open failed because the file didn't exist, then we know that --create
38
+ old_content = File.read(path)
39
+ rescue StandardError
40
+ # If File.read failed because the file didn't exist, then we know that --create
31
41
  # was specified due to the validation in validate_path.
32
42
  return "#{toc}\n"
33
43
  end
34
- begin
35
- old_content = T.must(f.read)
36
- ensure
37
- f.close
38
- end
39
44
 
40
45
  if Regexp.new(Regexp.escape(COMMENT_BEGIN), Regexp::IGNORECASE).match?(old_content)
41
46
  return old_content.gsub(
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mdtoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - andornaut
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-06 00:00:00.000000000 Z
11
+ date: 2026-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5'
19
+ version: '5.25'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5'
26
+ version: '5.25'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,56 +58,42 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.86'
61
+ version: '1.50'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.86'
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop-shopify
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: 1.0.4
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: 1.0.4
68
+ version: '1.50'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rubocop-sorbet
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '0.5'
75
+ version: 0.10.0
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '0.5'
82
+ version: 0.10.0
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: unparser
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: 0.4.9
89
+ version: 0.6.0
104
90
  type: :development
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
- version: 0.4.9
96
+ version: 0.6.0
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: sorbet-runtime
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -133,13 +119,13 @@ description: |
133
119
 
134
120
  * [Ruby](https://www.ruby-lang.org/en/) (see [.ruby-version](./.ruby-version))
135
121
 
136
- ```
137
- $ gem install mdtoc
122
+ ```bash
123
+ gem install mdtoc
138
124
  ```
139
125
 
140
126
  ## Usage
141
127
 
142
- ```
128
+ ```bash
143
129
  $ mdtoc --help
144
130
  Usage: mdtoc [options] files or directories...
145
131
  -h, --help Show this message
@@ -149,12 +135,15 @@ description: |
149
135
  ```
150
136
 
151
137
  1. Add a `<!-- mdtoc -->` tag to a Markdown file.
138
+
139
+ ```bash
140
+ echo '<!-- mdtoc -->' >> README.md
152
141
  ```
153
- $ echo '<!-- mdtoc -->` >> README.md
154
- ```
142
+
155
143
  2. Run `mdtoc` and specify input files or directories (eg. the "test/samples" directory) and an output file (eg. "README.md").
156
- ```
157
- $ mdtoc -aco README.md test/samples
144
+
145
+ ```bash
146
+ mdtoc -aco README.md test/samples
158
147
  ```
159
148
 
160
149
  ## Example Rakefile
@@ -162,29 +151,33 @@ description: |
162
151
  Create a `Rakefile` with the contents below, then run
163
152
  [`rake`](https://github.com/ruby/rake) to:
164
153
 
165
- * `git pull`
154
+ * `git pullgem push pkg/mdtoc-0.2.0.gem`
166
155
  * `git add` any *.md files
167
156
  * Run `mdtoc` to update the generated table of contents in the ./README.md file
168
157
  * Git commit and push any changes
169
158
 
170
- ```
159
+ ```ruby
171
160
  task default: %w[mdtoc]
172
161
 
173
162
  desc 'Update Markdown table of contents and push changes to the git repository'
174
- task :mdtoc do |t|
175
- command = <<~END
163
+ task :mdtoc do
164
+ command = <<~CMD
176
165
  set -e
177
- git pull
178
166
  if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
179
167
  echo 'Error: conflicts exist' >&2
180
168
  exit 1
181
169
  fi
182
170
  mdtoc --append --create --output README.md docs/
183
171
  git add *.md **/*.md
184
- git commit -m 'Update TOC'
172
+ git commit -qm 'Update TOC' || true
173
+ git pull
185
174
  git push
186
- END
187
- %x|#{command}|
175
+ CMD
176
+ sh command, verbose: false do |ok, status|
177
+ unless ok
178
+ fail "Failed with status: #{status.exitstatus}"
179
+ end
180
+ end
188
181
  end
189
182
  ```
190
183
 
@@ -192,38 +185,42 @@ description: |
192
185
 
193
186
  ## Development
194
187
 
195
- ### Installation
188
+ ### Setup
196
189
 
197
190
  Requirements:
198
191
 
199
192
  * [Bundler](https://bundler.io/)
193
+ * [chruby](https://github.com/postmodern/chruby) (recommended)
200
194
 
201
- ```
202
- # Install dependencies
203
- $ bundle
195
+ ```bash
196
+ # Setup development environment
197
+ bin/setup
204
198
  ```
205
199
 
206
- ### Usage
200
+ ### Tasks
207
201
 
208
- ```
202
+ ```bash
209
203
  # List rake tasks
210
204
  $ rake -T
211
- rake build # Build mdtoc-0.0.2.gem into the pkg directory
212
- rake default # Run the build, rubocop:auto_correct, sorbet and test tasks
213
- rake install # Build and install mdtoc-0.0.2.gem into system gems
214
- rake install:local # Build and install mdtoc-0.0.2.gem into system gems without...
215
- rake release[remote] # Create tag v0.0.2 and build and push mdtoc-0.0.2.gem to ru...
216
- rake rubocop # Run RuboCop
217
- rake rubocop:auto_correct # Auto-correct RuboCop offenses
218
- rake sorbet # Run the Sorbet type checker
219
- rake test # Run tests
220
-
205
+ rake build # Build gem into the pkg directory
206
+ rake default # Run the build, rubocop, sorbet and test tasks
207
+ rake install # Build and install gem into system gems
208
+ rake rubocop # Run RuboCop
209
+ rake sorbet # Run the Sorbet type checker
210
+ rake test # Run tests
211
+ ```
221
212
  # Run mdtoc with test inputs
222
213
  $ ruby -Ilib bin/mdtoc test/samples
223
214
 
224
215
  # Run mdtoc with test inputs, and write to a newly created output file
225
216
  $ f=$(mktemp) && ruby -Ilib bin/mdtoc -aco ${f} test/samples ; cat ${f}
226
217
  ```
218
+
219
+ ### Publishing
220
+
221
+ ```bash
222
+ rake release
223
+ ```
227
224
  email:
228
225
  executables:
229
226
  - mdtoc
@@ -233,6 +230,7 @@ files:
233
230
  - bin/mdtoc
234
231
  - lib/mdtoc.rb
235
232
  - lib/mdtoc/cli.rb
233
+ - lib/mdtoc/markdown/fragment_generator.rb
236
234
  - lib/mdtoc/markdown/header.rb
237
235
  - lib/mdtoc/markdown/parser.rb
238
236
  - lib/mdtoc/node.rb
@@ -241,7 +239,8 @@ files:
241
239
  homepage: https://github.com/andornaut/mdtoc
242
240
  licenses:
243
241
  - MIT
244
- metadata: {}
242
+ metadata:
243
+ rubygems_mfa_required: 'true'
245
244
  post_install_message:
246
245
  rdoc_options: []
247
246
  require_paths:
@@ -257,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
257
256
  - !ruby/object:Gem::Version
258
257
  version: '0'
259
258
  requirements: []
260
- rubygems_version: 3.1.4
259
+ rubygems_version: 3.4.10
261
260
  signing_key:
262
261
  specification_version: 4
263
262
  summary: Read Markdown files and output a table of contents