[Swift] CommandPlugin で クラス図を作る(CommandPlugin から CLI コマンドをキックする)

SwiftPackageManagerEyeCatch

     
⌛️ 2 min.
Swift Package で Command Plugin を作っていきます。
最終的には、Swift のコードをパースして、mermaid の classDiagram を出力するのがゴールです。

環境&対象

以下の環境で動作確認を行なっています。

  • 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 と編集しています。)

CommandPluginResult

まとめ

CommandPlugin から CLIコマンドを使用する

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 もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。

超便利です

SwiftUIViewsMastery

販売元のページは、こちらです。

SwiftUI 徹底入門

# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。

Swift学習におすすめの本

詳解Swift

Swift の学習には、詳解 Swift という書籍が、おすすめです。

著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。

最新版を購入するのがおすすめです。

現時点では、上記の Swift 5 に対応した第5版が最新版です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です