@@ -4,9 +4,6 @@ public class MultiFileContextManager {
44 private let workspaceProvider : WorkspaceProvider
55 private let parser : ProgrammingLanguageSyntaxParser
66
7- // cache so we don’t re-parse the file every time
8- // private var cachedSwiftDependenciesKeys: [String: String]?
9-
107 public init ( workspaceProvider: WorkspaceProvider , parser: ProgrammingLanguageSyntaxParser ) {
118 self . workspaceProvider = workspaceProvider
129 self . parser = parser
@@ -36,60 +33,9 @@ public class MultiFileContextManager {
3633 return files
3734 }
3835
39- /// List files within dependency directories
40- /// This is currently not used as it is too expensive to run
41- // private func listDependencyFiles() async -> [String] {
42- // guard let root = try? await workspaceProvider.getProjectRootURL() else { return [] }
43- // var files: [String] = []
44- // let fm = FileManager.default
45- // let depRoots: [URL] = [
46- // root.appendingPathComponent("Tuist/.build/checkouts", isDirectory: true),
47- // root.appendingPathComponent("SourcePackages/checkouts", isDirectory: true),
48- // root.appendingPathComponent(".swiftpm/xcode/checkout", isDirectory: true)
49- // ].filter { fm.fileExists(atPath: $0.path) }
50- //
51- // for base in depRoots {
52- // if let e = fm.enumerator(
53- // at: base,
54- // includingPropertiesForKeys: [.isRegularFileKey],
55- // options: [.skipsPackageDescendants] // keep this to avoid .xcodeproj/.app bundles
56- // ) {
57- // for case let url as URL in e {
58- // guard url.pathExtension.lowercased() == "swift" else { continue }
59- // // (Optional) only Sources, to avoid Tests/Examples
60- // // guard url.path.contains("/Sources/") else { continue }
61- // files.append(url.absoluteString)
62- // }
63- // }
64- // }
65- // return files
66- // }
67-
68- /// Looks up `swift-dependencies/Sources/Dependencies/DependencyValues.swift`
69- /// under common checkout roots relative to the workspace.
70- // func loadSwiftDependenciesDependencyValuesFile() async throws -> [String: String] {
71- // guard let root = try? await workspaceProvider.getProjectRootURL() else { return [:] }
72- //
73- // // candidate locations (Tuist SPM, Xcode SPM, .swiftpm)
74- // let candidates: [URL] = [
75- // root.appendingPathComponent("Tuist/.build/checkouts/swift-dependencies/Sources/Dependencies/DependencyValues.swift"),
76- // root.appendingPathComponent("SourcePackages/checkouts/swift-dependencies/Sources/Dependencies/DependencyValues.swift"),
77- // root.appendingPathComponent(".swiftpm/xcode/checkout/swift-dependencies/Sources/Dependencies/DependencyValues.swift"),
78- // ]
79- //
80- // let fm = FileManager.default
81- // guard let fileURL = candidates.first(where: { fm.fileExists(atPath: $0.path) }) else {
82- // return [:]
83- // }
84- //
85- // let src = try String(contentsOf: fileURL, encoding: .utf8)
86- // return parseDependencyValuesSource(src)
87- // }
88-
8936 public func readFileContents( ignoreWithinPaths: [ String ] ) async -> [ FileContent ] {
9037 let workspaceURLs = await listFilesInWorkspace ( ignoreWithinPaths: ignoreWithinPaths)
91- // let dependencyURLs = await listDependencyFiles()
92- let fileURLs = workspaceURLs // + dependencyURLs
38+ let fileURLs = workspaceURLs
9339 return fileURLs. compactMap { fileURLString in
9440 guard let fileURL = URL ( string: fileURLString) else { return nil }
9541 do {
@@ -128,7 +74,6 @@ public class MultiFileContextManager {
12874
12975 for (name, content) in allSymbols {
13076 if let current = currentSymbolName, current == name { continue }
131- // if ignoreWithinPaths.contains(where: { content.fileURL.contains($0) }) { continue }
13277
13378 if file. content. containsExactIdentifier ( name) {
13479 if relevant [ name] == nil {
@@ -147,45 +92,12 @@ public class MultiFileContextManager {
14792 return relevant
14893 }
14994
150- func retrieveUsedDependencyKeys( file: FileContent , allFiles: [ FileContent ] ) async -> [ RegisteredDependencyValue ] {
95+ private func retrieveUsedDependencyKeys( file: FileContent , allFiles: [ FileContent ] ) async -> [ RegisteredDependencyValue ] {
15196 let dependencyValuesExtensions = await scanProjectForDependencyKeys ( files: allFiles)
15297 let dependecyVariablesAndTypes = dependencyValuesExtensions. flatMap { getDependencySymbolsFromExtensionContent ( $0. symbol. content) }
15398 let usedDependencyKeys = file. content. extractDependencyReferences ( dependencies: dependecyVariablesAndTypes)
15499 return usedDependencyKeys
155100 }
156-
157-
158- // public func retrieveRelevantSymbolsForFileContent(
159- // file: FileContent,
160- // ignoreWithinPaths: [String] = []
161- // ) async -> [String: SymbolContent] {
162- // let currentSymbolName = parser.parse(file: file).first?.symbol.name
163- // let allSymbols = await classifyContentWithinFiles()
164- //
165- // // Build maps
166- // let propToType = await collectDependencyValueKeys(from: allSymbols) // "errorToastCoordinator" -> "ErrorToastCoordinator"
167- // let usedKeys = extractDependencyKeys(in: file.content) // e.g. {"errorToastCoordinator"}
168- //
169- // // Invert for quick lookup: type -> set of keys
170- // var keysByType: [String: Set<String>] = [:]
171- // for (prop, type) in propToType { keysByType[type, default: []].insert(prop) }
172- //
173- // var relevant: [String: SymbolContent] = [:]
174- //
175- // for (typeName, content) in allSymbols {
176- // if let current = currentSymbolName, current == typeName { continue }
177- // if ignoreWithinPaths.contains(where: { content.fileURL.contains($0) }) { continue }
178- //
179- // var isReferenced = file.content.containsExactIdentifier(typeName)
180- // if !isReferenced, let keys = keysByType[typeName], !usedKeys.isDisjoint(with: keys) {
181- // isReferenced = true
182- // }
183- //
184- // if isReferenced { relevant[typeName] = content }
185- // }
186- //
187- // return relevant
188- // }
189101
190102 private func mergeExtensionsIntoBaseDeclarations( _ symbols: inout [ SymbolContent ] ) {
191103 var indexesToRemove : [ Int ] = [ ]
@@ -210,118 +122,7 @@ public class MultiFileContextManager {
210122 }
211123 }
212124
213- /// Parses the DependencyValues.swift source and returns property -> type mapping.
214- // func parseDependencyValuesSource(_ src: String) -> [String: String] {
215- // var map: [String: String] = [:]
216- //
217- // // Typed properties
218- // if let re = try? NSRegularExpression(
219- // pattern: #"\bvar\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_?.<>]+)\s*\{"#
220- // ) {
221- // re.enumerateMatches(in: src, range: NSRange(src.startIndex..., in: src)) { m, _, _ in
222- // guard
223- // let m,
224- // let name = Range(m.range(at: 1), in: src).map({ String(src[$0]) }),
225- // let type = Range(m.range(at: 2), in: src).map({ String(src[$0]) })
226- // else { return }
227- // map[name] = type
228- // }
229- // }
230- //
231- // // Getter/setter using self[TypeName.self]
232- // if let re2 = try? NSRegularExpression(
233- // pattern: #"\bvar\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{[^}]*?self\[\s*([A-Za-z_][A-Za-z0-9_]*)\.self\s*\]"#,
234- // options: [.dotMatchesLineSeparators]
235- // ) {
236- // re2.enumerateMatches(in: src, range: NSRange(src.startIndex..., in: src)) { m, _, _ in
237- // guard
238- // let m,
239- // let name = Range(m.range(at: 1), in: src).map({ String(src[$0]) }),
240- // let type = Range(m.range(at: 2), in: src).map({ String(src[$0]) })
241- // else { return }
242- // if map[name] == nil { map[name] = type }
243- // }
244- // }
245- //
246- // return map
247- // }
248-
249- /// Builds map of DependencyValues property -> backing type.
250- /// 1) First tries from already parsed project symbols (your extensions).
251- /// 2) If empty, tries to load from swift-dependencies checkout quickly.
252- // func collectDependencyValueKeys(from symbols: [String: SymbolContent]) async -> [String: String] {
253- // var map: [String: String] = [:]
254- //
255- // // 1) Project-local extensions (what you already had)
256- // for (_, content) in symbols {
257- // guard content.symbol.kind == .extensionWord,
258- // content.symbol.name == "DependencyValues" else { continue }
259- //
260- // let src = content.content
261- //
262- // // Typed: var foo: TypeName {
263- // if let re = try? NSRegularExpression(
264- // pattern: #"\bvar\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([A-Za-z_][A-Za-z0-9_?.<>]+)\s*\{"#
265- // ) {
266- // re.enumerateMatches(in: src, range: NSRange(src.startIndex..., in: src)) { m, _, _ in
267- // guard
268- // let m,
269- // let name = Range(m.range(at: 1), in: src).map({ String(src[$0]) }),
270- // let type = Range(m.range(at: 2), in: src).map({ String(src[$0]) })
271- // else { return }
272- // map[name] = type
273- // }
274- // }
275- //
276- // // Getter body: self[TypeName.self]
277- // if let re2 = try? NSRegularExpression(
278- // pattern: #"\bvar\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{[^}]*?self\[\s*([A-Za-z_][A-Za-z0-9_]*)\.self\s*\]"#,
279- // options: [.dotMatchesLineSeparators]
280- // ) {
281- // re2.enumerateMatches(in: src, range: NSRange(src.startIndex..., in: src)) { m, _, _ in
282- // guard
283- // let m,
284- // let name = Range(m.range(at: 1), in: src).map({ String(src[$0]) }),
285- // let type = Range(m.range(at: 2), in: src).map({ String(src[$0]) })
286- // else { return }
287- // if map[name] == nil { map[name] = type }
288- // }
289- // }
290- // }
291- //
292- // if !map.isEmpty { return map } // ✅ found in project
293- //
294- // // 2) Fast fallback to the single file from swift-dependencies
295- // if let cached = cachedSwiftDependenciesKeys { return cached }
296- //
297- // if let fast = try? await loadSwiftDependenciesDependencyValuesFile(),
298- // !fast.isEmpty {
299- // cachedSwiftDependenciesKeys = fast
300- // return fast
301- // }
302- //
303- // return map // empty
304- // }
305-
306- // Extracts keys like `errorToastCoordinator` from `@Dependency(\.errorToastCoordinator)`
307- // private func extractDependencyKeys(in source: String) -> Set<String> {
308- // // Matches: @Dependency(\.fooBar)
309- // let pattern = #"@Dependency\s*\(\s*\\\.\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)"#
310- // guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return [] }
311- //
312- // var keys = Set<String>()
313- // let range = NSRange(source.startIndex..., in: source)
314- // regex.enumerateMatches(in: source, options: [], range: range) { match, _, _ in
315- // guard
316- // let match,
317- // let r = Range(match.range(at: 1), in: source)
318- // else { return }
319- // keys.insert(String(source[r]))
320- // }
321- // return keys
322- // }
323-
324- func scanProjectForDependencyKeys( files: [ FileContent ] ) async -> [ SymbolContent ] {
125+ private func scanProjectForDependencyKeys( files: [ FileContent ] ) async -> [ SymbolContent ] {
325126 let allSymbols : [ SymbolContent ] = files. flatMap { parser. parse ( file: $0) }
326127 let dependencyValueExtensions = allSymbols. filter {
327128 $0. symbol. kind == . extensionWord && $0. symbol. name == " DependencyValues "
@@ -331,7 +132,7 @@ public class MultiFileContextManager {
331132
332133 /// Extract every `var <prop>: <Type> { ... }` and/or `self[<Type>.self]` from an
333134 /// `extension DependencyValues { ... }` source string.
334- func getDependencySymbolsFromExtensionContent( _ content: String ) -> [ RegisteredDependencyValue ] {
135+ private func getDependencySymbolsFromExtensionContent( _ content: String ) -> [ RegisteredDependencyValue ] {
335136 var results = Set < RegisteredDependencyValue > ( )
336137
337138 // 1) Typed property form: `var fooBar: TypeName {`
@@ -352,35 +153,10 @@ public class MultiFileContextManager {
352153 }
353154 }
354155
355- // 2) Getter/setter body form: `var foo { get { self[TypeName.self] } ... }`
356- // (dotMatchesLineSeparators so it works across newlines)
357- // if let body = try? NSRegularExpression(
358- // pattern: #"\bvar\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{[^}]*?self\[\s*([A-Za-z_][A-Za-z0-9_?.<>]+)\.self\s*\]"#,
359- // options: [.dotMatchesLineSeparators]
360- // ) {
361- // let range = NSRange(content.startIndex..., in: content)
362- // body.enumerateMatches(in: content, options: [], range: range) { m, _, _ in
363- // guard
364- // let m,
365- // let nameR = Range(m.range(at: 1), in: content),
366- // let typeR = Range(m.range(at: 2), in: content)
367- // else { return }
368- // let varName = String(content[nameR])
369- // let typeName = String(content[typeR])
370- // // Don’t overwrite a typed match if it already exists
371- // results.insert(.init(variableName: varName, symbolName: typeName))
372- // }
373- // }
374-
375156 return Array ( results) //.flatMap { $0 }
376157 }
377158}
378159
379- struct RegisteredDependencyValue : Hashable {
380- let variableName : String
381- let symbolName : String
382- }
383-
384160extension String {
385161 /// Checks if the string contains an exact symbol match.
386162 /// Allows any character besides letters, numbers, and underscores as boundaries
0 commit comments