最終的には、Swift のコードをパースして、mermaid の classDiagram を出力するのがゴールです。
Sponsor Link
環境&対象
- macOS14.3 Beta
- Xcode 15.2
- iOS 17.2
- Swift 5.9
作りたい Plugin
指定した Package/Project のクラス構造を mermaid 形式で出力するプラグインを作ってみます。
全体の予定
CommandPlugin から CLI コマンドをキックする
初回に作った CommandPlugin から 前回作成した CLIコマンドを呼び出して使用するようにします。
Dependencies を追加
まずは、先に作った CLIコマンドに依存するように Package.swift を更新します。
# description 等も少しアップデートしています。
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "CommandPluginExample",
// ...snip...
.plugin(
name: "CommandPluginExample",
capability: .command(intent: .custom( verb: "CommandPluginExample",
description: "extract type info"),
permissions: [.writeToPackageDirectory(reason: "write type info to class.text file")]),
dependencies: ["swiftymermaid"]
),
]
// ...snip...
)
CommandPluginExample を修正
一番最初の回で作ったままになっていた CommandPluginExample のコードも修正していきます。
再利用しやすいように performCommand と outputMermaid という2つに分けて実装しました。
おおよそ、以下のような処理になります。
performCommand でやっていること
・PluginContext から CLIコマンドを取得
・arguments から出力ファイル名情報を取得
・outputMermaid を呼び出し
outputMermaid でやっていること
・対象フォルダ(String) に対して、CLI コマンドを構築
・コマンドを実行し、終了するまで待ち、出力を取得
・指定出力先に、出力
実装は以下のようになります。(上に書いたことをそのままコードにしています)
import PackagePlugin
import Foundation
@main
struct CommandPluginExample: CommandPlugin {
// Entry point for command plugins applied to Swift Packages.
func performCommand(context: PluginContext, arguments: [String]) async throws {
let swiftymermaid = try context.tool(named: "swiftymermaid")
let targetFolder = context.package.directory.string
var arguments = ArgumentExtractor(arguments)
let output = arguments.extractOption(named: "outputFile").first ?? ""
try outputMermaid(tool: swiftymermaid, targetFolder, to: output)
}
func outputMermaid(tool: PluginContext.Tool,_ folderURLString: String,
to outputFileURLString: String = "") throws {
let process = Process()
process.executableURL = URL(fileURLWithPath: tool.path.string)
process.arguments = ["\(folderURLString)"]
let outputPipe = Pipe()
process.standardOutput = outputPipe
try process.run()
process.waitUntilExit()
let mermaidData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let fileURL: URL = URL(filePath: (outputFileURLString=="") ? "classes.text" : outputFileURLString)
try mermaidData.write(to: fileURL)
}
}
実行してみる
実行すると以下のような動作になります。
出力されたファイルは以下です。
classDiagram
%% Actor.swift
class Actor1 {
>
}
%% Class.swift
class Class1 {
>
}
%% CommandPluginExample.swift
class CommandPluginExample {
>
}
%% CommandPluginExampleLib.swift
class CommandPluginExampleLib {
>
}
class Hatch.Symbol {
>
}
%% CommandPluginExampleLibParserTests.swift
class CommandPluginExampleLibParserTests {
>
}
%% Enum.swift
class Enum1 {
>
}
%% Package.swift
%% Protocol.swift
class Protocol1 {
>
}
%% Struct.swift
class Struct1 {
>
}
%% UnderstandingTests.swift
class UnderstandingTests {
>
}
%% swiftymermaid.swift
class SwiftyMermaid {
>
}
mermaid で表示すると以下のようになります。(前回と同様に、Hatch.Symbol -> Hatch_Symbol と編集しています。)
まとめ
CommandPlugin から CLIコマンドを使用する
- CommandPlugin の dependencies に CLIコマンドを追加する
- CLIコマンドの引数等は、performCommand の引数として渡される
- CLIコマンドの実行には、Process を使用する
- CLIコマンドの実行結果取得には、Pipe 等を使用する
当初の目標はほとんど完成したので、次回に微調整して終了予定です。
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
SwiftUI おすすめ本
SwiftUI を理解するには、以下の本がおすすめです。
SwiftUI ViewMatery
SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、便利です。
英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。
View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。
超便利です
販売元のページは、こちらです。
SwiftUI 徹底入門
# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。
Swift学習におすすめの本
詳解Swift
Swift の学習には、詳解 Swift という書籍が、おすすめです。
著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。
最新版を購入するのがおすすめです。
現時点では、上記の Swift 5 に対応した第5版が最新版です。
Sponsor Link