Skip to content

Commit

Permalink
Make core code sharable between targets
Browse files Browse the repository at this point in the history
  • Loading branch information
dfed committed Nov 26, 2023
1 parent c700705 commit 7f345be
Show file tree
Hide file tree
Showing 21 changed files with 213 additions and 161 deletions.
20 changes: 19 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,39 @@ let package = Package(
.package(url: "https://github.com/pointfreeco/swift-macro-testing", from: "0.2.0"),
],
targets: [
.target(name: "SafeDI", dependencies: [
"SafeDIMacros"
]),
.macro(
name: "SafeDIMacros",
dependencies: [
"SafeDICore",
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]
),
.target(name: "SafeDI", dependencies: ["SafeDIMacros"]),
.testTarget(
name: "SafeDIMacrosTests",
dependencies: [
"SafeDIMacros",
"SafeDICore",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
.product(name: "MacroTesting", package: "swift-macro-testing"), // TODO: write tests that use this!
]
),
.target(
name: "SafeDICore",
dependencies: [
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
]
),
.testTarget(
name: "SafeDICoreTests",
dependencies: [
"SafeDICore"
]
),
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@
import SwiftDiagnostics
import SwiftSyntax

final class BuilderVisitor: SyntaxVisitor {
public final class BuilderVisitor: SyntaxVisitor {

// MARK: Initialization

init() {
public init() {
super.init(viewMode: .sourceAccurate)
}

// MARK: SyntaxVisitor

override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
public override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
guard
let parent = node.parent,
let typedParent = MemberBlockItemSyntax(parent),
Expand All @@ -57,7 +57,7 @@ final class BuilderVisitor: SyntaxVisitor {
return .skipChildren
}

override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
public override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
guard
let parent = node.parent,
let typedParent = MemberBlockItemSyntax(parent),
Expand All @@ -83,7 +83,7 @@ final class BuilderVisitor: SyntaxVisitor {
return .skipChildren
}

override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
public override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
guard
let parent = node.parent,
let typedParent = MemberBlockItemSyntax(parent),
Expand All @@ -109,24 +109,28 @@ final class BuilderVisitor: SyntaxVisitor {
return .skipChildren
}

override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
if node.name.text == DependenciesMacro.decoratedStructName {
public override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
if node.name.text == DependenciesVisitor.decoratedStructName {
didFindDependencies = true
dependenciesVisitor.walk(node)
}
return .skipChildren
}

// MARK: Internal
// MARK: Public

var dependencies: [Dependency] {
public var dependencies: [Dependency] {
dependenciesVisitor.dependencies
}
var builtType: String? {
public var builtType: String? {
dependenciesVisitor.builtType
}
private(set) var didFindDependencies = false
private(set) var diagnostics = [Diagnostic]()
public private(set) var didFindDependencies = false
public private(set) var diagnostics = [Diagnostic]()

public static let macroName = "builder"
public static let decoratedStructName = "Builder"
public static let getDependenciesClosureName = "getDependencies"

// MARK: Private

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@
import SwiftDiagnostics
import SwiftSyntax

final class DependenciesVisitor: SyntaxVisitor {
public final class DependenciesVisitor: SyntaxVisitor {

// MARK: Initialization

init() {
public init() {
super.init(viewMode: .sourceAccurate)
}

// MARK: SyntaxVisitor

override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
public override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
// Check attributes and extract dependency source.
let dependencySources = node.attributes.dependencySources
guard dependencySources.isEmpty || dependencySources.count == 1 else {
Expand All @@ -42,7 +42,7 @@ final class DependenciesVisitor: SyntaxVisitor {
replacementNode = Syntax(AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: TokenSyntax(
TokenKind.identifier(ConstructedMacro.name),
TokenKind.identifier(Dependency.Source.constructedAttributeName),
presence: .present
)
)
Expand Down Expand Up @@ -157,7 +157,7 @@ final class DependenciesVisitor: SyntaxVisitor {
return .skipChildren
}

override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
public override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
guard
let parent = node.parent,
let typedParent = MemberBlockItemSyntax(parent),
Expand All @@ -183,8 +183,8 @@ final class DependenciesVisitor: SyntaxVisitor {
return .skipChildren
}

override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
if node.name.text == DependenciesMacro.buildMethodName {
public override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
if node.name.text == DependenciesVisitor.buildMethodName {
if didFindBuildMethod {
// We've already found a `build` method!
if
Expand Down Expand Up @@ -246,8 +246,8 @@ final class DependenciesVisitor: SyntaxVisitor {
return .skipChildren
}

override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
if node.name.text == DependenciesMacro.decoratedStructName {
public override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
if node.name.text == DependenciesVisitor.decoratedStructName {
guard node.modifiers.containsPublic else {
diagnostics.append(Diagnostic(
node: node.attributes,
Expand All @@ -272,7 +272,7 @@ final class DependenciesVisitor: SyntaxVisitor {
newAttributes.append(.attribute(
AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: .identifier(DependenciesMacro.decoratedStructName)
name: .identifier(DependenciesVisitor.decoratedStructName)
)
)
))
Expand All @@ -296,12 +296,16 @@ final class DependenciesVisitor: SyntaxVisitor {
}
}

// MARK: Internal
// MARK: Public

private(set) var didFindBuildMethod = false
private(set) var dependencies = [Dependency]()
private(set) var builtType: String?
private(set) var diagnostics = [Diagnostic]()
public private(set) var didFindBuildMethod = false
public private(set) var dependencies = [Dependency]()
public private(set) var builtType: String?
public private(set) var diagnostics = [Diagnostic]()

public static let macroName = "dependencies"
public static let decoratedStructName = "Dependencies"
public static let buildMethodName = "build"

// MARK: Private

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

struct Dependency: Codable, Equatable {
let property: Property
let source: Source
public struct Dependency: Codable, Equatable {
public let property: Property
public let source: Source

var isVariant: Bool {
public var isVariant: Bool {
switch source {
case .constructedInvariant, .providedInvariant, .singletonInvariant:
return false
Expand All @@ -31,7 +31,7 @@ struct Dependency: Codable, Equatable {
}
}

var isInvariant: Bool {
public var isInvariant: Bool {
switch source {
case .constructedInvariant, .providedInvariant, .singletonInvariant:
return true
Expand All @@ -40,16 +40,19 @@ struct Dependency: Codable, Equatable {
}
}

enum Source: Codable, Equatable {
public enum Source: Codable, Equatable {
case constructedInvariant
case providedInvariant
case singletonInvariant
case variant

init?(_ attributeText: String) {
if attributeText == ConstructedMacro.name {
public static let constructedAttributeName = "constructed"
public static let singletonAttributeName = "singleton"

public init?(_ attributeText: String) {
if attributeText == Self.constructedAttributeName {
self = .constructedInvariant
} else if attributeText == SingletonMacro.name {
} else if attributeText == Self.singletonAttributeName {
self = .singletonInvariant
} else {
return nil
Expand Down
28 changes: 28 additions & 0 deletions Sources/SafeDICore/Errors/DiagnosticError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Distributed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import SwiftDiagnostics
import SwiftSyntax

public protocol DiagnosticError: Error, CustomStringConvertible {
var diagnostic: DiagnosticMessage { get }

var fixIt: FixItMessage { get }
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,36 @@

import SwiftDiagnostics

enum FixableBuilderError: DiagnosticError {
public enum FixableBuilderError: DiagnosticError {
case missingDependencies
case unexpectedVariableDeclaration
case unexpectedInitializer
case unexpectedFuncationDeclaration

var description: String {
public var description: String {
switch self {
case .missingDependencies:
return "Missing nested `@\(DependenciesMacro.name) public struct \(DependenciesMacro.decoratedStructName)` declaration"
return "Missing nested `@\(DependenciesVisitor.macroName) public struct \(DependenciesVisitor.decoratedStructName)` declaration"
case .unexpectedVariableDeclaration:
return "Found unexpected variable declaration in `\(BuilderMacro.decoratedStructName)`"
return "Found unexpected variable declaration in `\(BuilderVisitor.decoratedStructName)`"
case .unexpectedInitializer:
return "Found unexpected initializer in `\(BuilderMacro.decoratedStructName)`"
return "Found unexpected initializer in `\(BuilderVisitor.decoratedStructName)`"
case .unexpectedFuncationDeclaration:
return "Found unexpected function declaration in `\(BuilderMacro.decoratedStructName)`"
return "Found unexpected function declaration in `\(BuilderVisitor.decoratedStructName)`"
}
}

var diagnostic: DiagnosticMessage {
DiagnosticMessage(error: self)
public var diagnostic: SwiftDiagnostics.DiagnosticMessage {
BuilderDiagnosticMessage(error: self)
}

var fixIt: FixItMessage {
FixItMessage(error: self)
public var fixIt: SwiftDiagnostics.FixItMessage {
BuilderFixItMessage(error: self)
}

struct DiagnosticMessage: SwiftDiagnostics.DiagnosticMessage {

let error: FixableBuilderError
// MARK: - BuilderDiagnosticMessage

private struct BuilderDiagnosticMessage: DiagnosticMessage {
var diagnosticID: MessageID {
MessageID(domain: "FixableBuilderError.DiagnosticMessage", id: error.description)
}
Expand All @@ -68,13 +67,17 @@ enum FixableBuilderError: DiagnosticError {
var message: String {
error.description
}

let error: FixableBuilderError
}

struct FixItMessage: SwiftDiagnostics.FixItMessage {
// MARK: - BuilderFixItMessage

private struct BuilderFixItMessage: FixItMessage {
var message: String {
switch error {
case .missingDependencies:
return "Create nested `@\(DependenciesMacro.name) struct \(DependenciesMacro.decoratedStructName)`"
return "Create nested `@\(DependenciesVisitor.macroName) struct \(DependenciesVisitor.decoratedStructName)`"
case .unexpectedVariableDeclaration:
return "Delete variable declaration"
case .unexpectedInitializer:
Expand Down
Loading

0 comments on commit 7f345be

Please sign in to comment.