Fix code quality: add doc comments, document DAG assumption, clarify implicitImports
This commit is contained in:
parent
9eab7ffc72
commit
cf9f762155
1 changed files with 48 additions and 3 deletions
|
|
@ -1,8 +1,11 @@
|
|||
import Foundation
|
||||
|
||||
/// Result of analyzing multiple GIR repositories together.
|
||||
///
|
||||
/// Resolves the full cross-package dependency graph and determines
|
||||
/// which `import` statements each generated file needs.
|
||||
/// which `import` statements each generated file needs. Used as input
|
||||
/// to per-package code generation (via `packageConfigs`) and for
|
||||
/// producing `@_exported import` umbrella re-exports in each module.
|
||||
public struct MultiPackageAnalysis {
|
||||
/// Maps Swift module name → parsed Repository.
|
||||
public let repositories: [String: Repository]
|
||||
|
|
@ -22,11 +25,22 @@ public struct MultiPackageAnalysis {
|
|||
/// dependencies (i.e., modules accessed transitively through a direct
|
||||
/// dep that re-exports them). Always empty in the re-export approach
|
||||
/// because transitive types come through re-exports.
|
||||
///
|
||||
/// Reserved for non-re-export approaches where transitive types require
|
||||
/// explicit imports. Currently empty in the re-export lattice design.
|
||||
public let implicitImports: [String: Set<String>]
|
||||
|
||||
/// Per-package `GenerationConfig` for driving per-type code generation.
|
||||
public let packageConfigs: [String: GenerationConfig]
|
||||
|
||||
/// Creates a new multi-package analysis result.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - repositories: Parsed GIR repositories keyed by Swift module name.
|
||||
/// - directDependencies: Direct dependencies derived from `<include>` elements.
|
||||
/// - transitiveDependencies: Transitive closure for `@_exported import` re-exports.
|
||||
/// - implicitImports: Implicit imports (empty in the re-export lattice design).
|
||||
/// - packageConfigs: Per-package `GenerationConfig` for code generation.
|
||||
public init(repositories: [String: Repository],
|
||||
directDependencies: [String: Set<String>],
|
||||
transitiveDependencies: [String: Set<String>],
|
||||
|
|
@ -43,13 +57,27 @@ public struct MultiPackageAnalysis {
|
|||
/// Analyzes multiple GIR `Repository` instances to produce a
|
||||
/// `MultiPackageAnalysis` with resolved cross-package imports.
|
||||
public struct MultiPackageAnalyzer {
|
||||
/// Configuration describing the monorepo's packages and their GIR paths.
|
||||
public let config: MonorepoConfig
|
||||
|
||||
/// Creates a new multi-package analyzer.
|
||||
///
|
||||
/// - Parameter config: The monorepo configuration listing all packages to analyze.
|
||||
public init(config: MonorepoConfig) {
|
||||
self.config = config
|
||||
}
|
||||
|
||||
/// Parses all GIR files and resolves the dependency graph.
|
||||
///
|
||||
/// Each package's `.gir` file is parsed, direct dependencies are extracted
|
||||
/// from `<include>` elements, and transitive closures are computed via
|
||||
/// memoized depth-first traversal assuming a DAG (no dependency cycles).
|
||||
/// Returns a fully resolved `MultiPackageAnalysis` with per-package
|
||||
/// `GenerationConfig` instances suitable for code generation.
|
||||
///
|
||||
/// - Throws: `ParserError` if any `.gir` file is malformed or unreadable.
|
||||
/// - Returns: A `MultiPackageAnalysis` with parsed repositories,
|
||||
/// dependency mappings, and generation configurations.
|
||||
public func analyze() throws -> MultiPackageAnalysis {
|
||||
var repositories: [String: Repository] = [:]
|
||||
var directDeps: [String: Set<String>] = [:]
|
||||
|
|
@ -72,6 +100,22 @@ public struct MultiPackageAnalyzer {
|
|||
// direct dep's transitive deps, transitively.
|
||||
var transitiveDeps: [String: Set<String>] = [:]
|
||||
|
||||
/// The dependency graph is a DAG (no cycles in GIR include chains).
|
||||
/// If cycles were present, `visited` detection would cut traversal
|
||||
/// and the cached result would be incomplete. This implementation
|
||||
/// is correct for the DAG case only.
|
||||
///
|
||||
/// Computes the transitive closure of dependencies for a module.
|
||||
/// Uses memoization (`transitiveDeps` cache) to avoid recomputation
|
||||
/// and a `visited` set to detect cycles (belt-and-suspenders for a
|
||||
/// DAG-only graph). The result is: all modules reachable from
|
||||
/// `module` by following direct dependencies transitively, minus
|
||||
/// `module` itself.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - module: The Swift module name to compute transitive deps for.
|
||||
/// - visited: Set of modules currently on the DFS stack (for cycle detection).
|
||||
/// - Returns: The transitive dependency set for `module`.
|
||||
func computeTransitive(for module: String, visited: inout Set<String>) -> Set<String> {
|
||||
if let cached = transitiveDeps[module] { return cached }
|
||||
visited.insert(module)
|
||||
|
|
@ -93,8 +137,9 @@ public struct MultiPackageAnalyzer {
|
|||
_ = computeTransitive(for: moduleName, visited: &visited)
|
||||
}
|
||||
|
||||
// implicitImports: in a re-export lattice there are no implicit
|
||||
// imports — every needed module is reached via transitive re-exports.
|
||||
// implicitImports: reserved for non-re-export approaches where
|
||||
// transitive types require explicit imports. Currently empty in
|
||||
// the re-export lattice design.
|
||||
var implicitImports: [String: Set<String>] = [:]
|
||||
for moduleName in config.packages.map(\.name) {
|
||||
implicitImports[moduleName] = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue