Skip to content

Commit

Permalink
Support StorybookPreview macro in Preview declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnEstropia committed Mar 14, 2024
1 parent 65ab543 commit 054113b
Show file tree
Hide file tree
Showing 6 changed files with 480 additions and 2 deletions.
19 changes: 19 additions & 0 deletions Development/Demo/MyBook.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,25 @@ let myBook = Book.init(
}
}


#Preview("Some title") {
#StorybookPreview<UILabel> {
BookPreview { _ in
let label = UILabel()
label.text = "UILabel 1"
return label
}
}
}

#Preview("Some title 2") {
#StorybookPreview<MyLabel> {
BookPreview { _ in
MyLabel(title: "MyLabel 2")
}
}
}

#StorybookPage<MyLabel> {
BookPreview { _ in
MyLabel(title: "Test")
Expand Down
18 changes: 18 additions & 0 deletions Sources/StorybookKit/StorybookKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,21 @@ public macro StorybookPage<Target>(
module: "StorybookMacrosPlugin",
type: "StorybookPageMacro"
)

@freestanding(expression)
public macro StorybookPreview(
title: String,
@ViewBuilder contents: @escaping () -> any View
) -> AnyView = #externalMacro(
module: "StorybookMacrosPlugin",
type: "StorybookPreviewMacro"
)

@freestanding(expression)
public macro StorybookPreview<Target>(
target: Target.Type = Target.self,
@ViewBuilder contents: @escaping () -> any View
) -> AnyView = #externalMacro(
module: "StorybookMacrosPlugin",
type: "StorybookPreviewMacro"
)
3 changes: 2 additions & 1 deletion Sources/StorybookMacrosPlugin/StorybookMacrosPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct StorybookMacrosPlugin: CompilerPlugin {
// MARK: CompilerPlugin

let providingMacros: [Macro.Type] = [
StorybookPageMacro.self
StorybookPageMacro.self,
StorybookPreviewMacro.self
]
}
4 changes: 3 additions & 1 deletion Sources/StorybookMacrosPlugin/StorybookPageMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ public struct StorybookPageMacro: DeclarationMacro {
"""
)
]

}


// MARK: Private

private static func parseArguments(
from node: some FreestandingMacroExpansionSyntax
) throws -> (
Expand Down
106 changes: 106 additions & 0 deletions Sources/StorybookMacrosPlugin/StorybookPreviewMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//
// Copyright (c) 2024 Eureka, Inc.
//
// 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 Foundation
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

// MARK: - StorybookPreviewMacro

public struct StorybookPreviewMacro: ExpressionMacro {

// MARK: Internal

/// Should match `Book._magicSubstring`
static let _magicSubstring: String = "__🤖🛠️_StorybookMagic_"

// MARK: ExpressionMacro

public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
let (title, closure) = try self.parseArguments(from: node)
let enumName = context.makeUniqueName(
self._magicSubstring
)
return .init(
stringLiteral: """
{
enum \(enumName): BookProvider {
static var bookBody: BookPage {
.init(
title: \(title),
destination: \(closure)
)
}
}
return \(enumName).bookBody.destination
}()
"""
)
}


// MARK: Private

private static func parseArguments(
from node: some FreestandingMacroExpansionSyntax
) throws -> (
title: ExprSyntax,
closure: ClosureExprSyntax
) {
var argumentsIterator = node.argumentList.makeIterator()
var title: ExprSyntax? = (node.genericArgumentClause?.arguments.first?.argument)
.flatMap { genericType -> TypeSyntaxProtocol? in
genericType.as(IdentifierTypeSyntax.self)
?? genericType.as(MemberTypeSyntax.self)
}
.map({ .init(stringLiteral: "_typeName(\($0).self)") })

var closure: ClosureExprSyntax? = node.trailingClosure
while let argument = argumentsIterator.next()?
.as(LabeledExprSyntax.self) {

switch argument.label?.text {

case "title"?:
title = argument.expression

case "target"?:
title = .init(stringLiteral: "_typeName(\(argument))")

case "contents"?:
closure = argument.expression
.as(ClosureExprSyntax.self)

default:
fatalError()
}
}
return (
title: title!,
closure: closure!
)
}
}

0 comments on commit 054113b

Please sign in to comment.