Skip to content

Commit 3291efc

Browse files
authored
Merge PR #148: plan 89: address Copilot review on PR #147
2 parents 0bfe882 + 6a6db67 commit 3291efc

1 file changed

Lines changed: 70 additions & 48 deletions

File tree

plan/89_toc-generator-directive.md

Lines changed: 70 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ summary: >-
66
Add a `<?toc?>...<?/toc?>` generated-section
77
directive that emits a nested list of the
88
current document's headings linked to their
9-
anchors (MDS036). Upgrade MDS035 (plan 88) to
9+
anchors (MDS037). Upgrade MDS035 (plan 88) to
1010
auto-fix each detected renderer-specific TOC
1111
token by replacing it with a `<?toc?>` block,
1212
which the directive then regenerates on
@@ -85,19 +85,29 @@ produces with default settings.
8585
### Generated content
8686

8787
A nested unordered list, one item per heading
88-
in source order. Each item links to a
89-
GitHub-flavor slug of the heading text:
90-
91-
- Lowercase the heading plain text.
92-
- Replace spaces with `-`.
93-
- Strip characters outside `[a-z0-9-_]`.
94-
- Disambiguate repeats by appending `-1`, `-2`, …
95-
in source order (matching goldmark-meta /
96-
GitHub's behavior).
97-
98-
Indentation is `<?listindent?>`-aware: use the
99-
same per-level indent as MDS016 (two spaces by
100-
default).
88+
in source order. Each item links to the same
89+
heading anchor mdsmith already computes for
90+
cross-file heading references.
91+
92+
Do not define a TOC-specific slug algorithm.
93+
Reuse the `slugify` function and the
94+
duplicate-disambiguation logic in
95+
[`internal/rules/crossfilereferenceintegrity/rule.go`][cfri]
96+
(used by `collectHeadingAnchors`). Move it
97+
into a shared package. `internal/mdtext/` is
98+
the natural home. Both rules then call shared
99+
code so anchors stay consistent. Repeated
100+
headings get `-1`, `-2`, … suffixes in source
101+
order, matching the reference-integrity rule.
102+
103+
[cfri]: ../internal/rules/crossfilereferenceintegrity/rule.go
104+
105+
Indentation uses the same per-level indent as
106+
the MDS016 `list-indent` rule's `spaces`
107+
setting (default 2). There is no
108+
`<?listindent?>` directive; indentation is a
109+
property of the emitted output, not a
110+
configurable parameter of `<?toc?>`.
101111

102112
List items respect the heading structure, not
103113
the raw level. Given H2 → H4 → H2, the tree is:
@@ -110,9 +120,14 @@ the raw level. Given H2 → H4 → H2, the tree is:
110120

111121
…not a flat list keyed on absolute level.
112122

113-
### Rule: MDS036 (toc)
123+
### Rule: MDS037 (toc)
124+
125+
Note on numbering: plan 89 originally claimed
126+
MDS036, but plan 51 shipped first and took
127+
MDS036 for `max-section-length`. MDS034 remains
128+
reserved for plan 86. Plan 89 takes MDS037.
114129

115-
- ID: `MDS036`
130+
- ID: `MDS037`
116131
- Name: `toc`
117132
- Category: `meta`
118133
- Default: enabled (generated sections are
@@ -135,25 +150,25 @@ MDS035 becomes a `FixableRule`. On `Fix`, for
135150
each matched directive line inside a paragraph:
136151

137152
- `[TOC]` (unresolved), `[[_TOC_]]`, `[[toc]]`,
138-
`${toc}` → replace the single line with:
153+
`${toc}` → replace the single line with the
154+
canonical empty generated-section block:
139155

140156
```text
141-
<?toc
142-
?>
157+
<?toc?>
143158
<?/toc?>
144159
```
145160

146-
The empty YAML body means "use defaults". A
147-
trailing newline separator is inserted if the
148-
surrounding paragraph would otherwise fuse
149-
the directive into adjacent text.
161+
The empty body means "use defaults". MDS035's
162+
Fix must also insert surrounding blank lines
163+
when the directive would otherwise fuse into
164+
adjacent paragraph text.
150165

151166
- `[TOC]` with a matching link reference
152167
definition → leave untouched (already
153168
suppressed by Check; must stay out of Fix).
154169

155170
The Fix output is plain `<?toc?>...<?/toc?>`
156-
with an **empty** body. MDS036 runs in a
171+
with an **empty** body. MDS037 runs in a
157172
subsequent pass of the same `mdsmith fix`
158173
invocation (mdsmith already supports
159174
multi-pass fix, used by MDS019/MDS021) and
@@ -165,10 +180,11 @@ and fall back only if needed.
165180

166181
### Interaction with existing rules
167182

168-
- MDS015 (blank line around fenced code /
169-
generated sections): the Fix output adds the
170-
required blank-line padding around the
171-
inserted block.
183+
- MDS015 only enforces blank lines around
184+
fenced code blocks, not generated-section
185+
markers. Blank-line padding around inserted
186+
`<?toc?>` blocks is MDS035's responsibility
187+
at Fix time, not MDS015's.
172188
- MDS020 (required-structure): no change; TOC
173189
blocks are not a required section.
174190
- MDS019 (catalog), MDS021 (include): orthogonal
@@ -191,39 +207,45 @@ and fall back only if needed.
191207

192208
## Tasks
193209

194-
1. Create the `<?toc?>` directive in a new
210+
1. Move `slugify` and the duplicate-anchor
211+
counter from
212+
`internal/rules/crossfilereferenceintegrity/`
213+
into a shared helper in `internal/mdtext/`.
214+
Update the reference-integrity rule to call
215+
the shared helper. No behavior change.
216+
2. Create the `<?toc?>` directive in a new
195217
`internal/rules/toc/` package using the
196218
shared `internal/archetype/gensection.Engine`
197-
(same engine as `catalog`). Add a slug
198-
helper in `internal/mdtext/` or the toc
199-
package. Register as MDS036 in category
200-
`meta`, enabled by default, `FixableRule`.
201-
2. Add MDS036 fixtures under
202-
`internal/rules/MDS036-toc/`: `good/` with a
219+
(same engine as `catalog`) and the shared
220+
slug helper from task 1. Register as MDS037
221+
in category `meta`, enabled by default,
222+
`FixableRule`.
223+
3. Add MDS037 fixtures under
224+
`internal/rules/MDS037-toc/`: `good/` with a
203225
correct body, `bad/` with a stale body to
204226
verify Check, `fixed/` with the expected
205227
output after Fix. Cover default parameters,
206228
custom `min-level`/`max-level`, single-level
207229
docs, and deeply nested structures.
208-
3. Upgrade MDS035 to `FixableRule`: replace
209-
matched directive lines with
210-
`<?toc?>\n<?/toc?>` blocks preserving
211-
surrounding blank lines; leave `[TOC]`
212-
untouched when a link-ref definition
230+
4. Upgrade MDS035 to `FixableRule`: replace
231+
matched directive lines with the canonical
232+
empty block `<?toc?>\n<?/toc?>`, inserting
233+
blank lines above and below as needed; leave
234+
`[TOC]` untouched when a link-ref definition
213235
suppresses Check; add `fixed/` fixtures for
214236
each of the four variants.
215-
4. Update MDS035's diagnostic message to point
216-
at `<?toc?>` (MDS036) instead of
237+
5. Update MDS035's diagnostic message to point
238+
at `<?toc?>` (MDS037) instead of
217239
`<?catalog?>` (MDS019); wording:
218-
`unsupported TOC directive \`{token}\`; use \`<?toc?>\` (MDS036)`
219-
5. Update MDS035 README (message + examples),
240+
`unsupported TOC directive \`{token}\`; use \`<?toc?>\` (MDS037)`
241+
6. Update MDS035 README (message + examples),
220242
plan 88 status/deviation note, and the
221243
renderer-portability section in
222244
[docs/background/markdown-linters.md][lnt].
223-
6. Update the generated-section archetype doc
245+
7. Update the generated-section archetype doc
224246
to list `toc` alongside `catalog` and
225247
`include`.
226-
7. Verify multi-pass `mdsmith fix` end-to-end:
248+
8. Verify multi-pass `mdsmith fix` end-to-end:
227249
starting from a document containing `[TOC]`,
228250
a single `fix` run must yield a populated
229251
`<?toc?>...<?/toc?>` block. Add an
@@ -240,7 +262,7 @@ and fall back only if needed.
240262
- [ ] `min-level` and `max-level` parameters
241263
gate which headings appear
242264
- [ ] `<?toc?>` with a stale body produces
243-
an MDS036 diagnostic on `check`
265+
an MDS037 diagnostic on `check`
244266
- [ ] MDS035 `fix` rewrites `[TOC]`,
245267
`[[_TOC_]]`, `[[toc]]`, and `${toc}`
246268
on their own line to
@@ -254,7 +276,7 @@ and fall back only if needed.
254276
- [ ] Merge driver regenerates `<?toc?>`
255277
bodies on conflict, same as `<?catalog?>`
256278
- [ ] MDS035 diagnostic message names
257-
`<?toc?>` (MDS036) as the replacement
279+
`<?toc?>` (MDS037) as the replacement
258280
- [ ] All tests pass: `go test ./...`
259281
- [ ] `go tool golangci-lint run` reports
260282
no issues

0 commit comments

Comments
 (0)