Skip to content

Commit 0758bcf

Browse files
committed
Merge main
2 parents 1064fbf + 490e864 commit 0758bcf

File tree

17 files changed

+435
-493
lines changed

17 files changed

+435
-493
lines changed

Package.swift

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ let package = Package(
2929
.product(name: "GraphViz", package: "GraphViz"),
3030
.product(name: "SwiftIndexStore", package: "swift-indexstore"),
3131
"Utils",
32+
"UseGraphCore"
3233
]
3334
),
3435
.executableTarget(
@@ -69,13 +70,13 @@ let package = Package(
6970
.target(
7071
name: "Utils"
7172
),
72-
.testTarget(
73-
name: "UseGraphTest",
74-
dependencies: [
75-
"UseGraphCore",
76-
.product(name: "SwiftSyntax", package: "swift-syntax"),
77-
.product(name: "SwiftParser", package: "swift-syntax"),
78-
]
79-
),
73+
// .testTarget(
74+
// name: "UseGraphTest",
75+
// dependencies: [
76+
// "UseGraphCore",
77+
// .product(name: "SwiftSyntax", package: "swift-syntax"),
78+
// .product(name: "SwiftParser", package: "swift-syntax"),
79+
// ]
80+
// ),
8081
]
8182
)

Sources/UseGraph/UseGraphCommand.swift

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
//
2-
// UseGraphCommand.swift
3-
//
4-
//
5-
// Created by Roman Gorbenko on 08.06.2024.
6-
//
7-
81
import ArgumentParser
92
import UseGraphFrontend
103

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Foundation
2+
import Utils
3+
4+
public struct Edge: CSVRepresentable {
5+
public var fields: [String] {
6+
["Source", "Target", "Type"]
7+
}
8+
9+
public var csvRepresentation: String {
10+
source + "," + target + "," + type
11+
}
12+
13+
let source: String
14+
let target: String
15+
let type = "directed"
16+
17+
public init(source: String, target: String) {
18+
self.source = source
19+
self.target = target
20+
}
21+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Utils
2+
3+
public struct Node: Hashable, CSVRepresentable {
4+
public var csvRepresentation: String {
5+
var fields = [id, moduleName, fileName]
6+
if let line {
7+
fields.append(line)
8+
}
9+
if let entityName {
10+
fields.append(entityName)
11+
}
12+
if let entityType {
13+
fields.append(entityType)
14+
}
15+
return fields.joined(separator: ",")
16+
}
17+
18+
public var fields: [String] {
19+
var fields = ["id", "moduleName", "fileName"]
20+
if line != nil {
21+
fields.append("line")
22+
}
23+
if entityName != nil {
24+
fields.append("entityName")
25+
}
26+
if entityType != nil {
27+
fields.append("entityType")
28+
}
29+
return fields
30+
}
31+
32+
public var id: String {
33+
moduleName + "." + (containerName ?? "") + (entityName ?? "") + "." + (entityType ?? "") + "." + usrs.joined(separator: ",")
34+
}
35+
36+
public let moduleName: String
37+
public let fileName: String
38+
public let line: String?
39+
public let containerName: String?
40+
public let entityName: String?
41+
public let entityType: String?
42+
public let usrs: Set<String>
43+
44+
public init(
45+
moduleName: String,
46+
fileName: String,
47+
line: String?,
48+
entityName: String?,
49+
containerName: String?,
50+
entityType: String?,
51+
usrs: Set<String> = Set<String>()
52+
) {
53+
self.moduleName = moduleName
54+
self.fileName = fileName
55+
self.line = line
56+
self.entityName = entityName
57+
self.containerName = containerName
58+
self.entityType = entityType
59+
self.usrs = usrs
60+
}
61+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
import GraphViz
3+
import Foundation
4+
5+
public enum OutpurtGraphBuilderError: Swift.Error {
6+
case buildGraphError
7+
}
8+
9+
public protocol OutputGraphBuilding {
10+
func buildGraphData(graph: Graph, format: Format) async throws -> Data
11+
}
12+
13+
public final class OutputGraphBuilder: OutputGraphBuilding {
14+
public init() {}
15+
16+
public func buildGraphData(graph: Graph, format: Format) async throws -> Data {
17+
print("Start building graph...")
18+
19+
return try await withCheckedThrowingContinuation { continuation in
20+
graph.render(using: .fdp, to: format) { [weak self] result in
21+
guard self != nil else { return }
22+
switch result {
23+
case let .success(data):
24+
continuation.resume(returning: data)
25+
case let .failure(failure):
26+
continuation.resume(throwing: OutpurtGraphBuilderError.buildGraphError)
27+
print(failure)
28+
}
29+
}
30+
}
31+
}
32+
}
Lines changed: 36 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,21 @@
11
import Foundation
22
import GraphViz
3+
import UseGraphCore
34
import Utils
45

5-
protocol CSVRepresentable {
6-
var csvRepresentation: String { get }
7-
var fields: [String] { get }
8-
}
9-
10-
struct EdgeCSV: CSVRepresentable {
11-
var fields: [String] {
12-
["Source", "Target", "Type"]
13-
}
14-
15-
let source: String
16-
let target: String
17-
let type = "directed"
18-
19-
var csvRepresentation: String {
20-
source + "," + target + "," + type
21-
}
22-
}
23-
246
enum OutputFormat {
257
case svg
268
case png
279
case gv
28-
10+
2911
public static func parse(format: String) throws -> OutputFormat {
3012
switch format.lowercased() {
3113
case "svg":
32-
.svg
14+
.svg
3315
case "png":
34-
.png
16+
.png
3517
case "gv":
36-
.gv
18+
.gv
3719
default:
3820
throw FormatError.formatIsNotCorrect
3921
}
@@ -42,100 +24,74 @@ enum OutputFormat {
4224

4325
final class GraphBuilder {
4426
static let shared = GraphBuilder()
45-
46-
private init() {}
47-
48-
private func createCSV(from recArray: [CSVRepresentable]) -> String {
49-
guard let fields = recArray.first?.fields else { return "" }
50-
var csvString = fields.joined(separator: ",") + "\n"
51-
for dct in recArray {
52-
csvString = csvString.appending(dct.csvRepresentation + "\n")
53-
}
54-
return csvString
27+
let csvBuilder: CSVBuilding
28+
let outputGraphBuilder: OutputGraphBuilding
29+
30+
private init(
31+
csvBuilder: CSVBuilding = CSVBuilder(),
32+
outputGraphBuilder: OutputGraphBuilding = OutputGraphBuilder()
33+
) {
34+
self.csvBuilder = csvBuilder
35+
self.outputGraphBuilder = outputGraphBuilder
5536
}
56-
37+
5738
func csvBuildGraph(edges: [UseGraphPeriphery.Edge]) {
58-
var uniqueSet = Set<Node>()
39+
var uniqueSet = Set<UseGraphCore.Node>()
5940
edges.map { [$0.from, $0.to] }.flatMap { $0 }.forEach { uniqueSet.insert($0) }
60-
61-
let edges = edges.map { EdgeCSV(source: $0.from.id, target: $0.to.id) }
62-
let edgesCSV = createCSV(from: edges)
63-
let nodesCSV = createCSV(from: Array(uniqueSet))
64-
41+
42+
let edges = edges.map { UseGraphCore.Edge(source: $0.from.id, target: $0.to.id) }
43+
let edgesCSV = csvBuilder.createCSV(from: edges)
44+
let nodesCSV = csvBuilder.createCSV(from: Array(uniqueSet))
45+
6546
let nodesUrl = URL(fileURLWithPath: #file).deletingLastPathComponent().appending(path: "Nodes.csv")
6647
let edgesUrl = URL(fileURLWithPath: #file).deletingLastPathComponent().appending(path: "Edges.csv")
67-
48+
6849
guard let edgesData = edgesCSV.data(using: .utf8),
6950
let nodesData = nodesCSV.data(using: .utf8) else { fatalError() }
7051
print(FileManager.default.createFile(atPath: edgesUrl.path(), contents: edgesData))
7152
print(FileManager.default.createFile(atPath: nodesUrl.path(), contents: nodesData))
7253
}
73-
54+
7455
func buildGraph(edges: [Edge], format: OutputFormat) async throws {
7556
switch format {
7657
case .svg, .png, .gv:
7758
guard let format = mapFormat(format: format) else { fatalError() }
78-
7959
let data = try await buildGraphData(edges: edges, format: format)
8060
let url = URL(fileURLWithPath: #file).deletingLastPathComponent().appending(path: "Graph.\(format.rawValue)")
81-
guard var fileContents = String(data: data, encoding: .utf8) else { fatalError() }
82-
if format == .gv {
83-
fileContents = removeSecondAndThirdLine(string: fileContents)
84-
}
85-
61+
guard let fileContents = String(data: data, encoding: .utf8) else { fatalError() }
62+
8663
print(FileManager.default.createFile(atPath: url.path(), contents: fileContents.data(using: .utf8)))
8764
Task {
8865
System.shared.run("open \(url.path())")
8966
}
9067
}
9168
}
92-
69+
9370
func buildGraphData(edges: [Edge], format: Format) async throws -> Data {
9471
var graph = Graph(directed: true)
95-
72+
9673
for edge in edges {
9774
graph.append(
98-
GraphViz.Edge(
99-
from: GraphViz.Node(edge.from.id),
100-
to: GraphViz.Node(edge.to.id)
101-
)
75+
GraphViz.Edge(
76+
from: GraphViz.Node(edge.from.id),
77+
to: GraphViz.Node(edge.to.id)
78+
)
10279
)
10380
}
104-
105-
graph.render(using: .circo, to: .svg, completion: { _ in })
106-
107-
print("Start building graph...")
108-
109-
return try await withCheckedThrowingContinuation { continuation in
110-
graph.render(using: .fdp, to: format) { [weak self] result in
111-
guard self != nil else { return }
112-
switch result {
113-
case let .success(data):
114-
continuation.resume(returning: data)
115-
case let .failure(failure):
116-
continuation.resume(throwing: BuildGraphError.buildGraphError)
117-
print(failure)
118-
}
119-
}
120-
}
121-
}
122-
123-
private func removeSecondAndThirdLine(string: String) -> String {
124-
var lines = string.split(separator: "\n")
125-
lines.removeSubrange(1 ... 2)
126-
return lines.joined(separator: "\n")
81+
82+
return try await outputGraphBuilder.buildGraphData(graph: graph, format: format)
12783
}
12884
}
12985

13086
extension GraphBuilder {
13187
func mapFormat(format: OutputFormat) -> Format? {
13288
switch format {
13389
case .svg:
134-
.svg
90+
.svg
13591
case .png:
136-
.png
92+
.png
13793
case .gv:
138-
.gv
94+
.gv
13995
}
14096
}
14197
}

Sources/UseGraphPeriphery/UseGraphDynamic.swift

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import PeripheryKit
55
import SourceGraph
66
import Configuration
77
import Scan
8+
import UseGraphCore
89
import Shared
910
import XcodeSupport
1011

@@ -28,46 +29,6 @@ struct EdgeWithoutReference: Hashable {
2829
let to: Node
2930
}
3031

31-
struct Node: Hashable, CSVRepresentable {
32-
var csvRepresentation: String {
33-
[moduleName, fileName, line, entityName ?? "", entityType ?? "", id].joined(separator: ",")
34-
}
35-
36-
var fields: [String] {
37-
["moduleName", "fileName", "line", "entityName", "entityType", "id"]
38-
}
39-
40-
var id: String {
41-
moduleName + "." + (containerName ?? "") + (entityName ?? "") + "." + (entityType ?? "") + "." + usrs.joined(separator: ",")
42-
}
43-
44-
public let moduleName: String
45-
public let fileName: String
46-
public let line: String
47-
public let containerName: String?
48-
public let entityName: String?
49-
public let entityType: String?
50-
public let usrs: Set<String>
51-
52-
public init(
53-
moduleName: String,
54-
fileName: String,
55-
line: String,
56-
entityName: String?,
57-
containerName: String?,
58-
entityType: String?,
59-
usrs: Set<String> = Set<String>()
60-
) {
61-
self.moduleName = moduleName
62-
self.fileName = fileName
63-
self.line = line
64-
self.entityName = entityName
65-
self.containerName = containerName
66-
self.entityType = entityType
67-
self.usrs = usrs
68-
}
69-
}
70-
7132
enum PathError: Error {
7233
case pathIsNotCorrect
7334
case shouldBeOnlyOnePath
@@ -106,6 +67,7 @@ public struct UseGraphPeripheryBuildCommand: AsyncParsableCommand {
10667
configuration.project = .init(projectPath)
10768
configuration.schemes = schemes.components(separatedBy: ",")
10869
}
70+
10971
let project = try Project(configuration: configuration)
11072
let driver = try project.driver()
11173
try driver.build()

0 commit comments

Comments
 (0)