Skip to content

Commit 7b61530

Browse files
committed
apply Dachary feedback and update to support yaml and shared toctree functionality
1 parent 1c6c715 commit 7b61530

File tree

13 files changed

+322
-83
lines changed

13 files changed

+322
-83
lines changed

audit-cli/README.md

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ With `-v` flag, also shows:
223223

224224
#### `analyze includes`
225225

226-
Analyze `include` directive relationships in RST files to understand file dependencies.
226+
Analyze `include` directive and `toctree` relationships in RST files to understand file dependencies.
227+
228+
This command recursively follows both `.. include::` directives and `.. toctree::` entries to show all files that are referenced from a starting file. This provides a complete picture of file dependencies including both content includes and table of contents structure.
227229

228230
**Use Cases:**
229231

@@ -232,6 +234,7 @@ This command helps writers:
232234
- Identify circular include dependencies (files included multiple times)
233235
- Document file relationships for maintenance
234236
- Plan refactoring of complex include structures
237+
- Understand table of contents structure and page hierarchies
235238

236239
**Basic Usage:**
237240

@@ -283,35 +286,35 @@ times (e.g., file A includes file C, and file B also includes file C), the file
283286
However, the tree view will show it in all locations where it appears, with subsequent occurrences marked as circular
284287
includes in verbose mode.
285288

286-
#### `analyze references`
289+
#### `analyze file-references`
287290

288-
Find all files that reference a target file through RST directives. This performs reverse dependency analysis, showing which files reference the target file through `include`, `literalinclude`, or `io-code-block` directives.
291+
Find all files that reference a target file through RST directives. This performs reverse dependency analysis, showing which files reference the target file through `include`, `literalinclude`, `io-code-block`, or `toctree` directives.
289292

290-
The command searches all RST files (both `.rst` and `.txt` extensions) in the source directory tree.
293+
The command searches all RST files (`.rst` and `.txt` extensions) and YAML files (`.yaml` and `.yml` extensions) in the source directory tree. YAML files are included because extract and release files contain RST directives within their content blocks.
291294

292295
**Use Cases:**
293296

294297
This command helps writers:
295298
- Understand the impact of changes to a file (what pages will be affected)
296299
- Find all usages of an include file across the documentation
297300
- Track where code examples are referenced
298-
- Identify orphaned files (files with no references)
301+
- Identify orphaned files (files with no references, including toctree entries)
299302
- Plan refactoring by understanding file dependencies
300303

301304
**Basic Usage:**
302305

303306
```bash
304307
# Find what references an include file
305-
./audit-cli analyze references path/to/includes/fact.rst
308+
./audit-cli analyze file-references path/to/includes/fact.rst
306309

307310
# Find what references a code example
308-
./audit-cli analyze references path/to/code-examples/example.js
311+
./audit-cli analyze file-references path/to/code-examples/example.js
309312

310313
# Get JSON output for automation
311-
./audit-cli analyze references path/to/file.rst --format json
314+
./audit-cli analyze file-references path/to/file.rst --format json
312315

313316
# Show detailed information with line numbers
314-
./audit-cli analyze references path/to/file.rst --verbose
317+
./audit-cli analyze file-references path/to/file.rst --verbose
315318
```
316319

317320
**Flags:**
@@ -438,39 +441,39 @@ include : 3 files, 4 references
438441

439442
```bash
440443
# Check if an include file is being used
441-
./audit-cli analyze references ~/docs/source/includes/fact-atlas.rst
444+
./audit-cli analyze file-references ~/docs/source/includes/fact-atlas.rst
442445

443446
# Find all pages that use a specific code example
444-
./audit-cli analyze references ~/docs/source/code-examples/connect.py
447+
./audit-cli analyze file-references ~/docs/source/code-examples/connect.py
445448

446449
# Get machine-readable output for scripting
447-
./audit-cli analyze references ~/docs/source/includes/fact.rst --format json | jq '.total_references'
450+
./audit-cli analyze file-references ~/docs/source/includes/fact.rst --format json | jq '.total_references'
448451

449452
# See exactly where a file is referenced (with line numbers)
450-
./audit-cli analyze references ~/docs/source/includes/intro.rst --verbose
453+
./audit-cli analyze file-references ~/docs/source/includes/intro.rst --verbose
451454

452455
# Quick check: just show the count
453-
./audit-cli analyze references ~/docs/source/includes/fact.rst --count-only
456+
./audit-cli analyze file-references ~/docs/source/includes/fact.rst --count-only
454457
# Output: 5
455458

456459
# Get list of files for piping to other commands
457-
./audit-cli analyze references ~/docs/source/includes/fact.rst --paths-only
460+
./audit-cli analyze file-references ~/docs/source/includes/fact.rst --paths-only
458461
# Output:
459462
# page1.rst
460463
# page2.rst
461464
# page3.rst
462465

463466
# Filter to only show include directives (not literalinclude or io-code-block)
464-
./audit-cli analyze references ~/docs/source/includes/fact.rst --directive-type include
467+
./audit-cli analyze file-references ~/docs/source/includes/fact.rst --directive-type include
465468

466469
# Filter to only show literalinclude references
467-
./audit-cli analyze references ~/docs/source/code-examples/example.py --directive-type literalinclude
470+
./audit-cli analyze file-references ~/docs/source/code-examples/example.py --directive-type literalinclude
468471

469472
# Combine filters: count only literalinclude references
470-
./audit-cli analyze references ~/docs/source/code-examples/example.py -t literalinclude -c
473+
./audit-cli analyze file-references ~/docs/source/code-examples/example.py -t literalinclude -c
471474

472475
# Combine filters: list files that use this as an io-code-block
473-
./audit-cli analyze references ~/docs/source/code-examples/query.js -t io-code-block --paths-only
476+
./audit-cli analyze file-references ~/docs/source/code-examples/query.js -t io-code-block --paths-only
474477
```
475478

476479
### Compare Commands

audit-cli/commands/analyze/analyze.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
// This package serves as the parent command for various analysis operations.
44
// Currently supports:
55
// - includes: Analyze include directive relationships in RST files
6-
// - references: Find all files that reference a target file
6+
// - file-references: Find all files that reference a target file
77
//
88
// Future subcommands could include analyzing cross-references, broken links, or content metrics.
99
package analyze
1010

1111
import (
1212
"github.com/mongodb/code-example-tooling/audit-cli/commands/analyze/includes"
13-
"github.com/mongodb/code-example-tooling/audit-cli/commands/analyze/references"
13+
filereferences "github.com/mongodb/code-example-tooling/audit-cli/commands/analyze/file-references"
1414
"github.com/spf13/cobra"
1515
)
1616

@@ -26,14 +26,14 @@ func NewAnalyzeCommand() *cobra.Command {
2626
2727
Currently supports:
2828
- includes: Analyze include directive relationships (forward dependencies)
29-
- references: Find all files that reference a target file (reverse dependencies)
29+
- file-references: Find all files that reference a target file (reverse dependencies)
3030
3131
Future subcommands may support analyzing cross-references, broken links, or content metrics.`,
3232
}
3333

3434
// Add subcommands
3535
cmd.AddCommand(includes.NewIncludesCommand())
36-
cmd.AddCommand(references.NewReferencesCommand())
36+
cmd.AddCommand(filereferences.NewFileReferencesCommand())
3737

3838
return cmd
3939
}

audit-cli/commands/analyze/references/analyzer.go renamed to audit-cli/commands/analyze/file-references/analyzer.go

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package references
1+
package filereferences
22

33
import (
44
"bufio"
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111

1212
"github.com/mongodb/code-example-tooling/audit-cli/internal/pathresolver"
13+
"github.com/mongodb/code-example-tooling/audit-cli/internal/rst"
1314
)
1415

1516
// Regular expressions for matching directives
@@ -32,9 +33,10 @@ var (
3233

3334
// AnalyzeReferences finds all files that reference the target file.
3435
//
35-
// This function searches through all RST files in the source directory to find
36-
// files that reference the target file using include, literalinclude, or
37-
// io-code-block directives.
36+
// This function searches through all RST files (.rst, .txt) and YAML files (.yaml, .yml)
37+
// in the source directory to find files that reference the target file using include,
38+
// literalinclude, or io-code-block directives. YAML files are included because extract
39+
// and release files contain RST directives within their content blocks.
3840
//
3941
// Parameters:
4042
// - targetFile: Absolute path to the file to analyze
@@ -62,7 +64,7 @@ func AnalyzeReferences(targetFile string) (*ReferenceAnalysis, error) {
6264
ReferencingFiles: []FileReference{},
6365
}
6466

65-
// Walk through all RST files in the source directory
67+
// Walk through all RST and YAML files in the source directory
6668
err = filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
6769
if err != nil {
6870
return err
@@ -73,9 +75,10 @@ func AnalyzeReferences(targetFile string) (*ReferenceAnalysis, error) {
7375
return nil
7476
}
7577

76-
// Only process RST files (.rst and .txt extensions)
78+
// Only process RST files (.rst, .txt) and YAML files (.yaml, .yml)
79+
// YAML files may contain RST directives in extract/release content blocks
7780
ext := filepath.Ext(path)
78-
if ext != ".rst" && ext != ".txt" {
81+
if ext != ".rst" && ext != ".txt" && ext != ".yaml" && ext != ".yml" {
7982
return nil
8083
}
8184

@@ -107,7 +110,7 @@ func AnalyzeReferences(targetFile string) (*ReferenceAnalysis, error) {
107110
// findReferencesInFile searches a single file for references to the target file.
108111
//
109112
// This function scans through the file line by line looking for include,
110-
// literalinclude, and io-code-block directives that reference the target file.
113+
// literalinclude, io-code-block, and toctree directives that reference the target file.
111114
//
112115
// Parameters:
113116
// - filePath: Path to the file to search
@@ -129,19 +132,33 @@ func findReferencesInFile(filePath, targetFile, sourceDir string) ([]FileReferen
129132
lineNum := 0
130133
inIOCodeBlock := false
131134
ioCodeBlockStartLine := 0
135+
inToctree := false
136+
toctreeStartLine := 0
132137

133138
for scanner.Scan() {
134139
lineNum++
135140
line := scanner.Text()
136141
trimmedLine := strings.TrimSpace(line)
137142

143+
// Check for toctree start (use shared regex from rst package)
144+
if rst.ToctreeDirectiveRegex.MatchString(trimmedLine) {
145+
inToctree = true
146+
toctreeStartLine = lineNum
147+
continue
148+
}
149+
138150
// Check for io-code-block start
139151
if ioCodeBlockRegex.MatchString(trimmedLine) {
140152
inIOCodeBlock = true
141153
ioCodeBlockStartLine = lineNum
142154
continue
143155
}
144156

157+
// Check if we're exiting toctree (unindented line that's not empty and not an option)
158+
if inToctree && len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
159+
inToctree = false
160+
}
161+
145162
// Check if we're exiting io-code-block (unindented line that's not empty)
146163
if inIOCodeBlock && len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
147164
inIOCodeBlock = false
@@ -205,6 +222,26 @@ func findReferencesInFile(filePath, targetFile, sourceDir string) ([]FileReferen
205222
continue
206223
}
207224
}
225+
226+
// Check for toctree entries (indented document names)
227+
if inToctree {
228+
// Skip empty lines and option lines (starting with :)
229+
if trimmedLine == "" || strings.HasPrefix(trimmedLine, ":") {
230+
continue
231+
}
232+
233+
// This is a document name in the toctree
234+
// Document names can be relative or absolute (starting with /)
235+
docName := trimmedLine
236+
if referencesToctreeTarget(docName, targetFile, sourceDir, filePath) {
237+
references = append(references, FileReference{
238+
FilePath: filePath,
239+
DirectiveType: "toctree",
240+
ReferencePath: docName,
241+
LineNumber: toctreeStartLine,
242+
})
243+
}
244+
}
208245
}
209246

210247
if err := scanner.Err(); err != nil {
@@ -250,6 +287,31 @@ func referencesTarget(refPath, targetFile, sourceDir, currentFile string) bool {
250287
return absResolvedPath == targetFile
251288
}
252289

290+
// referencesToctreeTarget checks if a toctree document name points to the target file.
291+
//
292+
// This function uses the shared rst.ResolveToctreePath to resolve the document name
293+
// and then compares it to the target file.
294+
//
295+
// Parameters:
296+
// - docName: The document name from the toctree (e.g., "intro" or "/includes/intro")
297+
// - targetFile: Absolute path to the target file
298+
// - sourceDir: Source directory (for resolving relative paths)
299+
// - currentFile: Path to the file containing the toctree
300+
//
301+
// Returns:
302+
// - bool: true if the document name points to the target file
303+
func referencesToctreeTarget(docName, targetFile, sourceDir, currentFile string) bool {
304+
// Use the shared toctree path resolution from rst package
305+
resolvedPath, err := rst.ResolveToctreePath(currentFile, docName)
306+
if err != nil {
307+
// If we can't resolve it, it doesn't match
308+
return false
309+
}
310+
311+
// Compare with target file
312+
return resolvedPath == targetFile
313+
}
314+
253315
// FilterByDirectiveType filters the analysis results to only include references
254316
// of the specified directive type.
255317
//

0 commit comments

Comments
 (0)