Skip to content

Commit 139c1b8

Browse files
committed
refactoring DocumentationTestHarness
1 parent d4698dd commit 139c1b8

3 files changed

Lines changed: 85 additions & 68 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// DocumentationFinder.swift
3+
// SyntaxKit
4+
//
5+
// Created by Leo Dion on 9/4/25.
6+
//
7+
8+
//protocol DocumentationFinder {
9+
// func searchForFiles(in: )
10+
//}
11+
12+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import Foundation
2+
3+
// MARK: - FileManager Extensions
4+
5+
6+
extension FileManager {
7+
/// Finds documentation files in multiple relative paths
8+
func findDocumentationFiles(in relativePaths: [String], relativeTo root: URL, pathExtensions: [String]) throws -> [String] {
9+
try relativePaths.flatMap{
10+
try findDocumentationFiles(in: $0, relativeTo: root, pathExtensions: pathExtensions)
11+
}
12+
}
13+
14+
/// Finds documentation files in a single directory or file
15+
func findDocumentationFiles(in relativePath: String, relativeTo root: URL, pathExtensions: [String]) throws -> [String] {
16+
let fullPath = root.appendingPathComponent(relativePath)
17+
var documentationFiles: [String] = []
18+
19+
if fileExists(atPath: fullPath.path) {
20+
if pathExtensions.contains(where: { relativePath.hasSuffix("." + $0) }) {
21+
// Single file with matching extension
22+
documentationFiles.append(relativePath)
23+
} else {
24+
// Directory - recursively find files with specified extensions
25+
let foundFileURLs = try findMarkdownFiles(in: fullPath, pathExtensions: pathExtensions)
26+
let relativePaths = foundFileURLs.map { fileURL in
27+
String(fileURL.path.dropFirst(root.path.count + 1))
28+
}
29+
documentationFiles.append(contentsOf: relativePaths)
30+
}
31+
}
32+
33+
return documentationFiles
34+
}
35+
36+
/// Recursively finds files with specified extensions in a directory
37+
func findMarkdownFiles(in directory: URL, pathExtensions: [String]) throws -> [URL] {
38+
let enumerator = self.enumerator(at: directory, includingPropertiesForKeys: nil)
39+
40+
var markdownFiles: [URL] = []
41+
42+
while let fileURL = enumerator?.nextObject() as? URL {
43+
if pathExtensions.contains(fileURL.pathExtension) {
44+
markdownFiles.append(fileURL)
45+
}
46+
}
47+
48+
return markdownFiles
49+
}
50+
}

Tests/SyntaxDocTests/DocumentationTestHarness.swift

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,27 @@ import Testing
55

66
/// Harness for extracting and testing documentation code examples
77
internal class DocumentationTestHarness {
8+
/// Project root directory calculated from the current file location
9+
private static let projectRoot: URL = {
10+
let currentFileURL = URL(fileURLWithPath: #file)
11+
return currentFileURL
12+
.deletingLastPathComponent() // Tests/SyntaxDocTests
13+
.deletingLastPathComponent() // Tests
14+
.deletingLastPathComponent() // Project root
15+
}()
16+
17+
/// Document paths to search for documentation files
18+
private static let docPaths = [
19+
"Sources/SyntaxKit/Documentation.docc",
20+
"README.md",
21+
"Examples",
22+
]
23+
24+
/// Default file extensions for documentation files
25+
private static let defaultPathExtensions = ["md"]
826
/// Validates all code examples in all documentation files
927
internal func validateAllExamples() async throws -> [ValidationResult] {
10-
let documentationFiles = try findDocumentationFiles()
28+
let documentationFiles = try DocumentationTestHarness.findDocumentationFiles()
1129
var allResults: [ValidationResult] = []
1230

1331
for filePath in documentationFiles {
@@ -362,54 +380,9 @@ internal class DocumentationTestHarness {
362380
#endif
363381

364382
/// Finds all documentation files containing code examples
365-
private func findDocumentationFiles() throws -> [String] {
366-
let currentFileURL = URL(fileURLWithPath: #file)
367-
let projectRoot =
368-
currentFileURL
369-
.deletingLastPathComponent() // Tests/SyntaxKitTests/Integration
370-
.deletingLastPathComponent() // Tests/SyntaxKitTests
371-
.deletingLastPathComponent() // Tests
372-
.deletingLastPathComponent() // Project root
373-
let docPaths = [
374-
"Sources/SyntaxKit/Documentation.docc",
375-
"README.md",
376-
"Examples",
377-
]
378-
379-
var documentationFiles: [String] = []
380-
381-
for docPath in docPaths {
382-
let fullPath = projectRoot.appendingPathComponent(docPath)
383-
384-
if FileManager.default.fileExists(atPath: fullPath.path) {
385-
if docPath.hasSuffix(".md") {
386-
documentationFiles.append(docPath)
387-
} else {
388-
// Recursively find .md files in directory
389-
let foundFiles = try findMarkdownFiles(in: fullPath, relativeTo: projectRoot)
390-
documentationFiles.append(contentsOf: foundFiles)
391-
}
392-
}
393-
}
394-
395-
return documentationFiles
396-
}
397-
398-
/// Recursively finds markdown files in a directory
399-
private func findMarkdownFiles(in directory: URL, relativeTo root: URL) throws -> [String] {
400-
let fileManager = FileManager.default
401-
let enumerator = fileManager.enumerator(at: directory, includingPropertiesForKeys: nil)
402-
403-
var markdownFiles: [String] = []
404-
405-
while let fileURL = enumerator?.nextObject() as? URL {
406-
if fileURL.pathExtension == "md" {
407-
let relativePath = String(fileURL.path.dropFirst(root.path.count + 1))
408-
markdownFiles.append(relativePath)
409-
}
410-
}
411-
412-
return markdownFiles
383+
@available(*, deprecated, message: "Use findDocumentationFiles(in:relativeTo:pathExtensions:) instead")
384+
private static func findDocumentationFiles() throws -> [String] {
385+
try FileManager.default.findDocumentationFiles(in: Self.docPaths, relativeTo: Self.projectRoot, pathExtensions: Self.defaultPathExtensions)
413386
}
414387

415388
/// Resolves a relative file path to absolute path (public for use by test methods)
@@ -419,28 +392,10 @@ internal class DocumentationTestHarness {
419392

420393
/// Resolves a relative file path to absolute path
421394
private func resolveFilePath(_ filePath: String) throws -> String {
422-
let currentFileURL: URL
423-
424-
// Handle #file which might be relative or absolute
425-
if #filePath.hasPrefix("/") {
426-
// #file is already absolute
427-
currentFileURL = URL(fileURLWithPath: #filePath)
428-
} else {
429-
// #file is relative, resolve it from current working directory
430-
currentFileURL = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
431-
.appendingPathComponent(#filePath)
432-
}
433-
434-
let projectRoot =
435-
currentFileURL
436-
.deletingLastPathComponent() // Tests/SyntaxDocTests
437-
.deletingLastPathComponent() // Tests
438-
.deletingLastPathComponent() // Project root
439-
440395
if filePath.hasPrefix("/") {
441396
return filePath
442397
} else {
443-
return projectRoot.appendingPathComponent(filePath).path
398+
return Self.projectRoot.appendingPathComponent(filePath).path
444399
}
445400
}
446401
}

0 commit comments

Comments
 (0)