最終的には、Swift のコードをパースして、mermaid の classDiagram を出力するのがゴールです。
Sponsor Link
環境&対象
- macOS14.3 Beta
- Xcode 15.2 beta
- iOS 17.2
- Swift 5.9
作りたい Plugin
指定した Package/Project のクラス構造を mermaid 形式で出力するプラグインを作ってみます。
全体の予定
CommandPlugin プロジェクトの作成
Xcode15 では、Swift Package の1つとして Command Plugin プロジェクトを作成することが簡単にできます。
Swift Package プロジェクト作成
(Xcode 中で) 以下の手順に沿って、Swift Package のプロジェクトを作成します。
- “File” – “New” – “Package…” を選択
- “Multiplatform” – “Other” – “Command Plug-in” を選択して “Next” を押下
- 適当な名前をつけて、保存(以降では、”CommandPluginExample” という名称で保存したとして説明します)
作成直後のプロジェクトは以下のようになっています。
Swift Package 設定(platforms)
Swift Package の設定は、Package.swift で行います。
デフォルトで作成される Package.swift では不足がありますので、追加していきます。
まずは、platform を追加します。
基本的に Xcode 上から使用される想定なので、macOS がサポートプラットフォームです。
ということで、platforms を追記します。
let package = Package(
name: "CommandPluginExample",
platforms: [
.macOS(.v14)
],
products: [
// Products can be used to vend plugins, making them visible to other packages
.........
Template 不具合修正(as of Xcode15.2)
おそらく Xcode の不具合だと思うのですが、以下のようなコードが、CommandPlugin 向けのテンプレートの後に生成されています。
#if canImport(XcodeProjectPlugin)
import XcodeProjectPlugin
extension MyCommandPlugin: XcodeCommandPlugin {
// Entry point for command plugins applied to Xcode projects.
func performCommand(context: XcodePluginContext, arguments: [String]) throws {
print("Hello, World!")
}
}
#endif
おおよそ正しいのですが、extension の対象が MyCommandPlugin になってしまっています。(MyCommandPlugin という class/struct はありません・・・・)
このままでは、”Cannot find type MyCommandPlugin in scope” というエラーになってしまうので、MyCommandPlugin を自分の Plugin 名(この記事では、CommandPluginExample) に修正します。
CommandPlugin からファイル出力
最初の一歩として CommandPlugin から外部にファイル出力してみます。
現時点で出力すべき情報は特にないので、”Hello World!” という文字列を持つ HelloWorld.txt を作成することにします。
Swift Package 設定(permissions)
Swift Package Plugin からファイルを書き出すためには、設定ファイルに書き出すことを明示しないといけません。
下記のように、targets の plugin/capability 定義に、permissions を追記します。
... snip ...
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.plugin(
name: "CommandPluginExample",
capability: .command(intent: .custom( verb: "CommandPluginExample",
description: "prints hello world"),
permissions: [.writeToPackageDirectory(reason: "store result info into file")])
),
]
)
上記のようにすることで、plugin 実行前に reason に設定した文字列がユーザーに提示されつつ ファイル書き出しを許可するかどうかの確認ダイアログが表示されます。
なお、ここで Cancel を選択されると、ファイルに出力することはできません。
CommandPlugin 実装(Hello world)
ここまでで ファイルに出力するように 設定できたので、Plugin を実装していきます。
CommandPlugin は、実行されると performCommand 関数が呼び出されますので、そこに実装していきます。
@main
struct CommandPluginExample: CommandPlugin {
// Entry point for command plugins applied to Swift Packages.
func performCommand(context: PluginContext, arguments: [String]) async throws {
// (1)
let helloWorldPath = URL(fileURLWithPath: context.package.directory.appending(subpath: "HelloWorld.txt").string)
// (2)
try "Hello World!".data(using: .utf8)!.write(to: helloWorldPath)
}
}
- (1): プロジェクトディレクトリ配下の “HelloWorld.txt” 向けの URL を作成
- (2): “Hello World!” を ファイルに出力
performCommand には その引数として 引数情報 arguments: [String] と合わせて context: PluginContext が渡されてきます。
上記の例では、この context からパッケージのパスを取得して、HelloWorld.txt のパスを生成しています。
実行すると以下のような動作になります。
まとめ
SwiftPackage で CommandPlugin の作成を開始しました
- Xcode の新規 Package で “Command Plug-in” を選択すると簡単
- 生成されているコードが少しおかしいので修正が必要(as of Xcode15.2)
- 生成されている Package.swift には、platform が定義されていないので追記が必要
- ファイルを書き出すならば、Package.swift に追記が必要
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
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