mdtoc 0.1.5 → 0.2.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 +4 -4
- data/bin/mdtoc +1 -1
- data/lib/mdtoc/cli.rb +8 -8
- data/lib/mdtoc/markdown/header.rb +5 -4
- data/lib/mdtoc/markdown/parser.rb +6 -6
- data/lib/mdtoc/node.rb +6 -6
- data/lib/mdtoc/version.rb +1 -1
- data/lib/mdtoc/writer.rb +3 -3
- data/lib/mdtoc.rb +5 -5
- metadata +49 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67fab334c40c8a785d1ac0bcca6234a1fc048ad479ed7fb4df093f0eb14c2116
|
4
|
+
data.tar.gz: c80647e458fd2ceaa60189688d0c7a831ad023a20cb471fcc37d512e382db627
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e6e9abb89b30d7abed179b42b00a8d871ab7b5ea6b96a4607ea5284bed3a1e1b2bb3355e0258d84498b78c8dba1463ab170f46e9c4c7963f4931b2efa910483
|
7
|
+
data.tar.gz: a3c414d2472f1f2ad976bc02eca284c9b4f522ee21624ad30534d33563242cb2ac04457cf33a4bc1998f2af232f4aa803c2051ee066f910444d6f881c7b69396
|
data/bin/mdtoc
CHANGED
data/lib/mdtoc/cli.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
4
|
+
require "optparse"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
require "tempfile"
|
7
7
|
|
8
8
|
module Mdtoc
|
9
9
|
module CLI
|
@@ -14,19 +14,19 @@ module Mdtoc
|
|
14
14
|
def parse(args)
|
15
15
|
parser = OptionParser.new do |parser_|
|
16
16
|
parser_.banner = "Usage: #{parser_.program_name} [options] files or directories..."
|
17
|
-
parser_.on(
|
17
|
+
parser_.on("-h", "--help", "Show this message") do
|
18
18
|
puts parser_
|
19
19
|
exit
|
20
20
|
end
|
21
|
-
parser_.on(
|
22
|
-
parser_.on(
|
23
|
-
parser_.on(
|
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")
|
23
|
+
parser_.on("-c", "--[no-]create", "Create the --output file if it does not exist")
|
24
24
|
end
|
25
25
|
|
26
26
|
options = Options.new
|
27
27
|
options.paths = parser.parse(args, into: options)
|
28
28
|
if options.paths.empty?
|
29
|
-
warn(
|
29
|
+
warn("Specify at least one file or directory to read")
|
30
30
|
exit(1)
|
31
31
|
end
|
32
32
|
options
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "sorbet-runtime"
|
5
5
|
|
6
6
|
module Mdtoc
|
7
7
|
module Markdown
|
@@ -13,6 +13,7 @@ module Mdtoc
|
|
13
13
|
if depth < 0
|
14
14
|
raise ArgumentError, "Header depth must be >= 0, but was #{depth}"
|
15
15
|
end
|
16
|
+
|
16
17
|
@depth = depth
|
17
18
|
@label = normalize_label(label)
|
18
19
|
@url = url
|
@@ -20,7 +21,7 @@ module Mdtoc
|
|
20
21
|
|
21
22
|
sig { returns(String) }
|
22
23
|
def to_s
|
23
|
-
prefix =
|
24
|
+
prefix = " " * 2 * @depth
|
24
25
|
"#{prefix}* [#{@label}](#{@url})"
|
25
26
|
end
|
26
27
|
|
@@ -32,7 +33,7 @@ module Mdtoc
|
|
32
33
|
private
|
33
34
|
|
34
35
|
def normalize_label(label)
|
35
|
-
label = label.strip.tr("\t\n\r",
|
36
|
+
label = label.strip.tr("\t\n\r", "") # Remove whitespace characters other than spaces.
|
36
37
|
label.gsub(/\[(.*)\]\(.*\)/, '\1') # Remove links
|
37
38
|
end
|
38
39
|
end
|
@@ -41,7 +42,7 @@ module Mdtoc
|
|
41
42
|
sig { params(depth: Integer, label: String, url: String).void }
|
42
43
|
def initialize(depth, label, url)
|
43
44
|
super
|
44
|
-
@url += "##{@label.downcase.tr(
|
45
|
+
@url += "##{@label.downcase.tr(" ", "-").gsub(/[^\w\-]/, "")}"
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require_relative
|
4
|
+
require "sorbet-runtime"
|
5
|
+
require_relative "header"
|
6
6
|
|
7
7
|
module Mdtoc
|
8
8
|
module Markdown
|
@@ -22,10 +22,10 @@ module Mdtoc
|
|
22
22
|
skip = T.let(false, T::Boolean)
|
23
23
|
lines.filter_map do |line|
|
24
24
|
# Skip code blocks.
|
25
|
-
if line.start_with?(
|
25
|
+
if line.start_with?("```") && !T.must(line[3..]).strip.end_with?("```")
|
26
26
|
skip = !skip
|
27
27
|
end
|
28
|
-
next if skip || !line.start_with?(
|
28
|
+
next if skip || !line.start_with?("#")
|
29
29
|
|
30
30
|
header(line)
|
31
31
|
end
|
@@ -36,9 +36,9 @@ module Mdtoc
|
|
36
36
|
sig { params(line: String).returns(HeaderWithFragment) }
|
37
37
|
def header(line)
|
38
38
|
m = T.must(line.strip.match(/^(#+)\s*(.*)$/))
|
39
|
-
num_hashes = m[1]&.count(
|
39
|
+
num_hashes = m[1]&.count("#") || 1
|
40
40
|
depth = @depth + num_hashes - 1
|
41
|
-
label = m[2] ||
|
41
|
+
label = m[2] || ""
|
42
42
|
HeaderWithFragment.new(depth, label, @url)
|
43
43
|
end
|
44
44
|
end
|
data/lib/mdtoc/node.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require_relative
|
7
|
-
require_relative
|
4
|
+
require "pathname"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
require_relative "markdown/header"
|
7
|
+
require_relative "markdown/parser"
|
8
8
|
|
9
9
|
module Mdtoc
|
10
10
|
class Node
|
@@ -43,7 +43,7 @@ module Mdtoc
|
|
43
43
|
|
44
44
|
sig { returns(String) }
|
45
45
|
def label
|
46
|
-
File.basename(@path, File.extname(@path)).gsub(/_+/,
|
46
|
+
File.basename(@path, File.extname(@path)).gsub(/_+/, " ").gsub(/\s+/, " ").capitalize
|
47
47
|
end
|
48
48
|
|
49
49
|
class DirNode < Node
|
@@ -52,7 +52,7 @@ module Mdtoc
|
|
52
52
|
readme_path = T.let(nil, T.nilable(String))
|
53
53
|
child_headers = Dir
|
54
54
|
.each_child(@path)
|
55
|
-
.reject { |path| readme_path = File.join(@path, path) if path.casecmp?(
|
55
|
+
.reject { |path| readme_path = File.join(@path, path) if path.casecmp?("readme.md") }
|
56
56
|
.sort!
|
57
57
|
.flat_map { |path| Node.for_path(File.join(@path, path), @depth + 1).headers }
|
58
58
|
return child_headers unless readme_path
|
data/lib/mdtoc/version.rb
CHANGED
data/lib/mdtoc/writer.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
|
4
4
|
module Mdtoc
|
5
5
|
module Writer
|
6
|
-
COMMENT_BEGIN =
|
7
|
-
COMMENT_END =
|
6
|
+
COMMENT_BEGIN = "<!-- mdtoc -->"
|
7
|
+
COMMENT_END = "<!-- mdtoc-end -->"
|
8
8
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
@@ -13,7 +13,7 @@ module Mdtoc
|
|
13
13
|
def write(toc, path, append, create)
|
14
14
|
validate_path(path, create)
|
15
15
|
new_content = content(toc, path, append)
|
16
|
-
File.open(path,
|
16
|
+
File.open(path, "w") do |f|
|
17
17
|
f.write(new_content)
|
18
18
|
end
|
19
19
|
end
|
data/lib/mdtoc.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
4
|
+
require "optparse"
|
5
|
+
require "tempfile"
|
6
|
+
require_relative "mdtoc/cli"
|
7
|
+
require_relative "mdtoc/node"
|
8
|
+
require_relative "mdtoc/writer"
|
9
9
|
|
10
10
|
module Mdtoc
|
11
11
|
class << self
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- andornaut
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-29 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,56 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
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: '
|
68
|
+
version: '1.50'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop-shopify
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 2.0.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 2.0.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop-sorbet
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 0.10.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 0.10.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: unparser
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
103
|
+
version: 0.6.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 0.6.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: sorbet-runtime
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,13 +133,13 @@ description: |
|
|
133
133
|
|
134
134
|
* [Ruby](https://www.ruby-lang.org/en/) (see [.ruby-version](./.ruby-version))
|
135
135
|
|
136
|
-
```
|
137
|
-
|
136
|
+
```bash
|
137
|
+
gem install mdtoc
|
138
138
|
```
|
139
139
|
|
140
140
|
## Usage
|
141
141
|
|
142
|
-
```
|
142
|
+
```bash
|
143
143
|
$ mdtoc --help
|
144
144
|
Usage: mdtoc [options] files or directories...
|
145
145
|
-h, --help Show this message
|
@@ -149,12 +149,15 @@ description: |
|
|
149
149
|
```
|
150
150
|
|
151
151
|
1. Add a `<!-- mdtoc -->` tag to a Markdown file.
|
152
|
+
|
153
|
+
```bash
|
154
|
+
echo '<!-- mdtoc -->' >> README.md
|
152
155
|
```
|
153
|
-
|
154
|
-
```
|
156
|
+
|
155
157
|
2. Run `mdtoc` and specify input files or directories (eg. the "test/samples" directory) and an output file (eg. "README.md").
|
156
|
-
|
157
|
-
|
158
|
+
|
159
|
+
```bash
|
160
|
+
mdtoc -aco README.md test/samples
|
158
161
|
```
|
159
162
|
|
160
163
|
## Example Rakefile
|
@@ -167,24 +170,28 @@ description: |
|
|
167
170
|
* Run `mdtoc` to update the generated table of contents in the ./README.md file
|
168
171
|
* Git commit and push any changes
|
169
172
|
|
170
|
-
```
|
173
|
+
```ruby
|
171
174
|
task default: %w[mdtoc]
|
172
175
|
|
173
176
|
desc 'Update Markdown table of contents and push changes to the git repository'
|
174
|
-
task :mdtoc do
|
175
|
-
command = <<~
|
177
|
+
task :mdtoc do
|
178
|
+
command = <<~CMD
|
176
179
|
set -e
|
177
|
-
git pull
|
178
180
|
if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
|
179
181
|
echo 'Error: conflicts exist' >&2
|
180
182
|
exit 1
|
181
183
|
fi
|
182
184
|
mdtoc --append --create --output README.md docs/
|
183
185
|
git add *.md **/*.md
|
184
|
-
git commit -
|
186
|
+
git commit -qm 'Update TOC' || true
|
187
|
+
git pull
|
185
188
|
git push
|
186
|
-
|
187
|
-
|
189
|
+
CMD
|
190
|
+
sh command, verbose: false do |ok, status|
|
191
|
+
unless ok
|
192
|
+
fail "Failed with status: #{status.exitstatus}"
|
193
|
+
end
|
194
|
+
end
|
188
195
|
end
|
189
196
|
```
|
190
197
|
|
@@ -192,31 +199,32 @@ description: |
|
|
192
199
|
|
193
200
|
## Development
|
194
201
|
|
195
|
-
###
|
202
|
+
### Setup
|
196
203
|
|
197
204
|
Requirements:
|
198
205
|
|
199
206
|
* [Bundler](https://bundler.io/)
|
200
207
|
|
201
|
-
```
|
208
|
+
```bash
|
202
209
|
# Install dependencies
|
203
|
-
|
210
|
+
bundle
|
204
211
|
```
|
205
212
|
|
206
|
-
###
|
213
|
+
### Tasks
|
207
214
|
|
208
|
-
```
|
215
|
+
```bash
|
209
216
|
# List rake tasks
|
210
217
|
$ rake -T
|
211
|
-
rake build
|
212
|
-
rake default
|
213
|
-
rake install
|
214
|
-
rake install:local
|
215
|
-
rake release[remote]
|
216
|
-
rake rubocop
|
217
|
-
rake rubocop:
|
218
|
-
rake
|
219
|
-
rake
|
218
|
+
rake build # Build mdtoc-0.1.5.gem into the pkg directory
|
219
|
+
rake default # Run the build, rubocop:autocorrect_all, sorbet and test tasks
|
220
|
+
rake install # Build and install mdtoc-0.1.5.gem into system gems
|
221
|
+
rake install:local # Build and install mdtoc-0.1.5.gem into system gems without network access
|
222
|
+
rake release[remote] # Create tag v0.1.5 and build and push mdtoc-0.1.5.gem to rubygems.org
|
223
|
+
rake rubocop # Run RuboCop
|
224
|
+
rake rubocop:autocorrect # Autocorrect RuboCop offenses (only when it's safe)
|
225
|
+
rake rubocop:autocorrect_all # Autocorrect RuboCop offenses (safe and unsafe)
|
226
|
+
rake sorbet # Run the Sorbet type checker
|
227
|
+
rake test # Run tests
|
220
228
|
|
221
229
|
# Run mdtoc with test inputs
|
222
230
|
$ ruby -Ilib bin/mdtoc test/samples
|
@@ -257,7 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
265
|
- !ruby/object:Gem::Version
|
258
266
|
version: '0'
|
259
267
|
requirements: []
|
260
|
-
rubygems_version: 3.
|
268
|
+
rubygems_version: 3.2.3
|
261
269
|
signing_key:
|
262
270
|
specification_version: 4
|
263
271
|
summary: Read Markdown files and output a table of contents
|