Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ Packages/
Package.pins
Package.resolved
.build/

# Bazel
bazel-*
57 changes: 57 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
load(
"@build_bazel_rules_swift//swift:swift.bzl",
"swift_binary",
"swift_library",
)

swift_library(
name = "NeedleFoundation",
srcs = glob(
["Sources/NeedleFoundation/**/*.swift"],
allow_empty = False,
),
module_name = "NeedleFoundation",
visibility = ["//visibility:public"],
)

swift_binary(
name = "needle",
visibility = ["//visibility:public"],
deps = [
":NeedleLib",
],
)

swift_library(
name = "NeedleLib",
srcs = glob(
[
"Generator/Sources/needle/**/*.swift",
],
allow_empty = False,
),
copts = ["-suppress-warnings"],
module_name = "Needle",
deps = [
":NeedleFramework",
"@SwiftToolsSupportCore//:TSCBasic",
"@UberSwiftCommon//:CommandFramework",
],
)

swift_library(
name = "NeedleFramework",
srcs = glob(
[
"Generator/Sources/NeedleFramework/**/*.swift",
],
allow_empty = False,
),
copts = ["-suppress-warnings"],
module_name = "NeedleFramework",
deps = [
"@SwiftSyntax//:SwiftParser_opt",
"@UberSwiftCommon//:SourceParsingFramework",
"@UberSwiftConcurrency//:Concurrency",
],
)
62 changes: 31 additions & 31 deletions Generator/Sources/NeedleFramework/Entry/Generator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ public class Generator {
/// concurrently. `nil` if no limit is set.
/// - throws: `GenericError`.
public final func generate(from sourceRootPaths: [String], withSourcesListFormat sourcesListFormatValue: String? = nil, excludingFilesEndingWith exclusionSuffixes: [String], excludingFilesWithPaths exclusionPaths: [String], with additionalImports: [String], _ headerDocPath: String?, to destinationPath: String, shouldCollectParsingInfo: Bool, parsingTimeout: TimeInterval, exportingTimeout: TimeInterval, retryParsingOnTimeoutLimit: Int, concurrencyLimit: Int?, emitInputsDepsFile: Bool) throws {
let processor: ProcessorType = .generateSource(additionalImports: additionalImports,
headerDocPath: headerDocPath,
destinationPath: destinationPath,
let processor: ProcessorType = .generateSource(additionalImports: additionalImports,
headerDocPath: headerDocPath,
destinationPath: destinationPath,
exportingTimeout: exportingTimeout)
try processSourceCode(from: sourceRootPaths,
withSourcesListFormat: sourcesListFormatValue,
excludingFilesEndingWith: exclusionSuffixes,
excludingFilesWithPaths: exclusionPaths,
shouldCollectParsingInfo: shouldCollectParsingInfo,
parsingTimeout: parsingTimeout,
retryParsingOnTimeoutLimit: retryParsingOnTimeoutLimit,
try processSourceCode(from: sourceRootPaths,
withSourcesListFormat: sourcesListFormatValue,
excludingFilesEndingWith: exclusionSuffixes,
excludingFilesWithPaths: exclusionPaths,
shouldCollectParsingInfo: shouldCollectParsingInfo,
parsingTimeout: parsingTimeout,
retryParsingOnTimeoutLimit: retryParsingOnTimeoutLimit,
concurrencyLimit: concurrencyLimit,
processorType: processor,
emitInputsDepsFile: emitInputsDepsFile)
Expand Down Expand Up @@ -108,22 +108,22 @@ public class Generator {
/// concurrently. `nil` if no limit is set.
/// - throws: `GenericError`.
public final func printDependencyTree(from sourceRootPaths: [String],
withSourcesListFormat sourcesListFormatValue: String? = nil,
excludingFilesEndingWith exclusionSuffixes: [String],
withSourcesListFormat sourcesListFormatValue: String? = nil,
excludingFilesEndingWith exclusionSuffixes: [String],
excludingFilesWithPaths exclusionPaths: [String],
shouldCollectParsingInfo: Bool,
shouldCollectParsingInfo: Bool,
parsingTimeout: TimeInterval,
retryParsingOnTimeoutLimit: Int,
retryParsingOnTimeoutLimit: Int,
concurrencyLimit: Int?,
rootComponentName: String) throws {
let processor: ProcessorType = .printDIStructure(rootComponentName: rootComponentName)
try processSourceCode(from: sourceRootPaths,
withSourcesListFormat: sourcesListFormatValue,
excludingFilesEndingWith: exclusionSuffixes,
excludingFilesWithPaths: exclusionPaths,
shouldCollectParsingInfo: shouldCollectParsingInfo,
parsingTimeout: parsingTimeout,
retryParsingOnTimeoutLimit: retryParsingOnTimeoutLimit,
try processSourceCode(from: sourceRootPaths,
withSourcesListFormat: sourcesListFormatValue,
excludingFilesEndingWith: exclusionSuffixes,
excludingFilesWithPaths: exclusionPaths,
shouldCollectParsingInfo: shouldCollectParsingInfo,
parsingTimeout: parsingTimeout,
retryParsingOnTimeoutLimit: retryParsingOnTimeoutLimit,
concurrencyLimit: concurrencyLimit,
processorType: processor,
emitInputsDepsFile: false)
Expand All @@ -139,7 +139,7 @@ public class Generator {
}

// MARK: - Private

private enum ProcessorType {
case generateSource(additionalImports: [String], headerDocPath: String?, destinationPath: String, exportingTimeout: TimeInterval)
case printDIStructure(rootComponentName: String)
Expand All @@ -154,19 +154,19 @@ public class Generator {
}

private func processSourceCode(from sourceRootPaths: [String],
withSourcesListFormat sourcesListFormatValue: String? = nil,
excludingFilesEndingWith exclusionSuffixes: [String],
excludingFilesWithPaths exclusionPaths: [String],
shouldCollectParsingInfo: Bool,
withSourcesListFormat sourcesListFormatValue: String? = nil,
excludingFilesEndingWith exclusionSuffixes: [String],
excludingFilesWithPaths exclusionPaths: [String],
shouldCollectParsingInfo: Bool,
parsingTimeout: TimeInterval,
retryParsingOnTimeoutLimit: Int,
retryParsingOnTimeoutLimit: Int,
concurrencyLimit: Int?,
processorType: ProcessorType,
emitInputsDepsFile: Bool) throws {
let sourceRootUrls = sourceRootPaths.map { (path: String) -> URL in
URL(path: path)
}

let executor = createExecutor(withName: "Needle.generate", shouldTrackTaskId: shouldCollectParsingInfo, concurrencyLimit: concurrencyLimit)

var retryParsingCount = 0
Expand Down Expand Up @@ -198,9 +198,9 @@ public class Generator {
}

private func printDIStructure(from sourceRootUrls: [URL],
withSourcesListFormat sourcesListFormatValue: String? = nil,
excludingFilesEndingWith exclusionSuffixes: [String],
excludingFilesWithPaths exclusionPaths: [String],
withSourcesListFormat sourcesListFormatValue: String? = nil,
excludingFilesEndingWith exclusionSuffixes: [String],
excludingFilesWithPaths exclusionPaths: [String],
withExecutor executor: SequenceExecutor,
withParsingTimeout parsingTimeout: TimeInterval,
withRootComponentName rootComponentName: String) throws {
Expand Down
24 changes: 14 additions & 10 deletions Generator/Sources/NeedleFramework/Parsing/BaseVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,23 @@ class BaseVisitor: SyntaxVisitor {
var varNestingLevel = 0

let filePath: String

init(filePath: String) {
self.filePath = filePath
super.init(viewMode: .sourceAccurate)
}

/// Whether we are parsing the line of code which declares a Component.
/// We need this flag to determine if the generic argument we parse later is for the Component.
var isParsingComponentDeclarationLine: Bool = false

override func visitPost(_ node: FunctionCallExprSyntax) {
if let callexpr = node.calledExpression.firstToken?.text,
let currentEntityName = currentEntityNode?.typeName {
componentToCallExprs[currentEntityName, default: []].insert(callexpr)
}
}

override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
varNestingLevel += 1
return .visitChildren
Expand All @@ -71,20 +71,24 @@ class BaseVisitor: SyntaxVisitor {
return Property(name: propertyName, type: propertyType, isInternal: isInternal)
}
}

propertiesDict[currentEntityName, default: []].append(contentsOf: memberProperties)
}

override func visitPost(_ node: ImportDeclSyntax) {
let importStatement = node.withoutTrivia().description.trimmed
imports.append(importStatement)
#if swift(>=5.9)
let importStatement = node.trimmed
#else
let importStatement = node.withoutTrivia()
#endif
imports.append(importStatement.description.trimmed)
}

override func visit(_ node: MemberDeclBlockSyntax) -> SyntaxVisitorContinueKind {
isParsingComponentDeclarationLine = false
return .visitChildren
}

override func visitPost(_ node: SourceFileSyntax) {
if currentEntityNode == nil {
imports = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import Concurrency
import Foundation
import SourceParsingFramework
#if swift(>=5.6)
#if swift(>=5.9)
import SwiftParser
#elseif swift(>=5.6)
import SwiftSyntaxParser
#else
import SwiftSyntax
Expand All @@ -42,7 +44,11 @@ class ASTProducerTask: AbstractTask<AST> {
/// - returns: The `AST` data model.
/// - throws: Any error occurred during execution.
override func execute() throws -> AST {
#if swift(>=5.9)
let syntax = try Parser.parse(source: sourceContent)
#else
let syntax = try SyntaxParser.parse(sourceUrl)
#endif
return AST(sourceHash: MD5(string: sourceContent), sourceFileSyntax: syntax, filePath: sourceUrl.path)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class DeclarationsParserTask: AbstractTask<DependencyGraphNode> {
// MARK: - Private

private let ast: AST

private func parseSyntax() throws -> ([ASTComponent], [Dependency], [String]) {
let visitor = Visitor(sourceHash: ast.sourceHash, filePath: ast.filePath)
visitor.walk(ast.sourceFileSyntax)
Expand All @@ -56,14 +56,14 @@ class DeclarationsParserTask: AbstractTask<DependencyGraphNode> {
private final class Visitor: BaseVisitor {
private(set) var dependencies: [Dependency] = []
private(set) var components: [ASTComponent] = []

private let sourceHash: String

init(sourceHash: String, filePath: String) {
self.sourceHash = sourceHash
super.init(filePath: filePath)
}

override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
if node.isDependency {
currentEntityNode = node
Expand All @@ -72,7 +72,7 @@ private final class Visitor: BaseVisitor {
return .skipChildren
}
}

override func visitPost(_ node: ProtocolDeclSyntax) {
let protocolName = node.typeName
if protocolName == currentEntityNode?.typeName {
Expand All @@ -82,7 +82,7 @@ private final class Visitor: BaseVisitor {
dependencies.append(dependency)
}
}

override func visit(_ node: ClassDeclSyntax) ->SyntaxVisitorContinueKind {
if node.isComponent {
isParsingComponentDeclarationLine = true
Expand All @@ -92,7 +92,7 @@ private final class Visitor: BaseVisitor {
return .skipChildren
}
}

override func visitPost(_ node: ClassDeclSyntax) {
let componentName = node.typeName
if componentName == currentEntityNode?.typeName {
Expand All @@ -109,12 +109,12 @@ private final class Visitor: BaseVisitor {
components.append(component)
}
}

override func visitPost(_ node: GenericArgumentListSyntax) {
guard isParsingComponentDeclarationLine else {return }
currentDependencyProtocol = node.first?.argumentType.description.trimmed.removingModulePrefix
}

override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
return .skipChildren
}
Expand Down
Loading