Skip to content

Commit 7b264c1

Browse files
Merge pull request #4 from thousandyears/oliver/swift-package-manager-plugin
Add CLI and Swift Package Manager Plugin
2 parents 8acf8cc + ebbca92 commit 7b264c1

15 files changed

Lines changed: 287 additions & 84 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,4 @@ fastlane/test_output
9090
# https://github.com/johnno1962/injectionforxcode
9191

9292
iOSInjectionProject/
93+
.swiftpm/

Package.resolved

Lines changed: 29 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.5
1+
// swift-tools-version: 5.6
22

33
import PackageDescription
44

@@ -14,100 +14,99 @@ let package = Package(
1414
.library(name: "SwiftStandAlone", targets: ["SwiftStandAlone"]),
1515
.library(name: "KotlinStandAlone", targets: ["KotlinStandAlone"]),
1616
.library(name: "LexiconGenerators", targets: ["LexiconGenerators"]),
17+
.executable(name: "lexicon-generate", targets: ["lexicon-generate"]),
18+
.plugin(name: "SwiftStandAloneGeneratorPlugin", targets: ["SwiftStandAloneGeneratorPlugin"]),
19+
.plugin(name: "SwiftLibraryGeneratorPlugin", targets: ["SwiftLibraryGeneratorPlugin"]),
1720
],
1821
dependencies: [
19-
.package(url: "https://github.com/screensailor/Hope", .branch("trunk")),
22+
.package(url: "https://github.com/screensailor/Hope", branch: "trunk"),
2023
.package(url: "https://github.com/apple/swift-collections", from: "1.0.0"),
24+
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.1.2")
2125
],
2226
targets: [
23-
24-
// MARK: Lexicon
25-
2627
.target(
2728
name: "Lexicon",
2829
dependencies: [
2930
.product(name: "Collections", package: "swift-collections")
3031
],
31-
swiftSettings: [.define("EDITOR")] // TODO: meke this opt in
32+
swiftSettings: [.define("EDITOR")] // TODO: make this opt in
3233
),
3334
.testTarget(
3435
name: "LexiconTests",
3536
dependencies: [
3637
"Hope",
3738
"Lexicon"
3839
],
39-
resources: [
40-
.copy("Resources")
40+
resources: [.copy("Resources")]
41+
),
42+
.target(
43+
name: "LexiconGenerators",
44+
dependencies: [
45+
"Lexicon",
46+
"SwiftLexicon",
47+
"SwiftStandAlone",
48+
"KotlinStandAlone"
49+
]
50+
),
51+
.target(
52+
name: "SwiftLexicon",
53+
dependencies: [
54+
"Lexicon"
4155
]
4256
),
43-
44-
// MARK: LexiconGenerators
45-
46-
.target(
47-
name: "LexiconGenerators",
48-
dependencies: [
49-
"Lexicon",
50-
"SwiftLexicon",
51-
"SwiftStandAlone",
52-
"KotlinStandAlone"
53-
]
54-
),
55-
56-
// MARK: SwiftLexicon
57-
58-
.target(
59-
name: "SwiftLexicon",
60-
dependencies: [
61-
"Lexicon",
62-
]
63-
),
6457
.testTarget(
6558
name: "SwiftLexiconTests",
6659
dependencies: [
6760
"Hope",
6861
"SwiftLexicon"
6962
],
70-
resources: [
71-
.copy("Resources"),
63+
resources: [.copy("Resources")]
64+
),
65+
.target(
66+
name: "SwiftStandAlone",
67+
dependencies: [
68+
"Lexicon",
7269
]
7370
),
74-
75-
// MARK: SwiftStandAlone
76-
77-
.target(
78-
name: "SwiftStandAlone",
79-
dependencies: [
80-
"Lexicon",
81-
]
82-
),
8371
.testTarget(
8472
name: "SwiftStandAloneTests",
8573
dependencies: [
8674
"Hope",
8775
"SwiftStandAlone"
8876
],
89-
resources: [
90-
.copy("Resources"),
77+
resources: [.copy("Resources")]
78+
),
79+
.target(
80+
name: "KotlinStandAlone",
81+
dependencies: [
82+
"Lexicon",
9183
]
9284
),
93-
94-
// MARK: KotlinStandAlones
95-
96-
.target(
97-
name: "KotlinStandAlone",
98-
dependencies: [
99-
"Lexicon",
100-
]
101-
),
10285
.testTarget(
10386
name: "KotlinStandAloneTests",
10487
dependencies: [
10588
"Hope",
10689
"KotlinStandAlone"
10790
],
108-
resources: [
109-
.copy("Resources"),
91+
resources: [.copy("Resources")]
92+
),
93+
.executableTarget(
94+
name: "lexicon-generate",
95+
dependencies: [
96+
.target(name: "LexiconGenerators"),
97+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
98+
.product(name: "Collections", package: "swift-collections")
11099
]
111100
),
101+
.plugin(
102+
name: "SwiftStandAloneGeneratorPlugin",
103+
capability: .buildTool(),
104+
dependencies: ["lexicon-generate"]
105+
),
106+
.plugin(
107+
name: "SwiftLibraryGeneratorPlugin",
108+
capability: .buildTool(),
109+
dependencies: ["lexicon-generate"]
110+
)
112111
]
113112
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main
5+
struct SwiftLibraryGeneratorPlugin: BuildToolPlugin {
6+
7+
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
8+
let lexicon = try context.tool(named: "lexicon-generate")
9+
let output = context.pluginWorkDirectory.appending("GeneratedSources")
10+
return FileManager.default.enumerator(atPath: target.directory.string)?
11+
.compactMap { value in (value as? String).map(target.directory.appending) }
12+
.filter { path in (path.extension ?? "").hasSuffix("lexicon") }
13+
.map { input in
14+
let file = output.appending(input.stem)
15+
return .buildCommand(
16+
displayName: "Generate \(input)",
17+
executable: lexicon.path,
18+
arguments: [
19+
input.string,
20+
"--output", file.string,
21+
"--type", "swift"
22+
],
23+
inputFiles: [input],
24+
outputFiles: [file]
25+
)
26+
} ?? []
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main
5+
struct SwiftStandAloneGeneratorPlugin: BuildToolPlugin {
6+
7+
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
8+
let lexicon = try context.tool(named: "lexicon-generate")
9+
let output = context.pluginWorkDirectory.appending("GeneratedSources")
10+
return FileManager.default.enumerator(atPath: target.directory.string)?
11+
.compactMap { value in (value as? String).map(target.directory.appending) }
12+
.filter { path in (path.extension ?? "").hasSuffix("lexicon") }
13+
.map { input in
14+
let file = output.appending(input.stem)
15+
return .buildCommand(
16+
displayName: "Generate \(input)",
17+
executable: lexicon.path,
18+
arguments: [
19+
input.string,
20+
"--output", file.string,
21+
"--type", "swift-standalone"
22+
],
23+
inputFiles: [input],
24+
outputFiles: [file]
25+
)
26+
} ?? []
27+
}
28+
}

Sources/KotlinStandAlone/Generator.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ public enum Generator: CodeGenerator {
99

1010
// TODO: prefixes?
1111

12-
public static let utType = UTType.sourceCode
12+
public static let utType = UTType(filenameExtension: "kt", conformingTo: .sourceCode)!
13+
public static let command = "kotlin"
1314

1415
public static func generate(_ json: Lexicon.Graph.JSON) throws -> Data {
1516
return Data(json.kotlin().utf8)

Sources/Lexicon/CodeGenerator.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ import UniformTypeIdentifiers
66

77
public protocol CodeGenerator {
88
static var utType: UTType { get }
9+
static var command: String { get }
910
static func generate(_ json: Lexicon.Graph.JSON) throws -> Data
1011
}

Sources/Lexicon/JSONClasses.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import UniformTypeIdentifiers
88
public enum JSONClasses: CodeGenerator {
99

1010
public static let utType: UTType = .json
11-
11+
public static let command = "json"
12+
1213
public static func generate(_ json: Lexicon.Graph.JSON) throws -> Data {
1314
let encoder = Encoder()
1415
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]

Sources/Lexicon/Lemma.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,15 @@ extension Lemma {
358358

359359
func lazy_ownType() -> [ID: Unowned<Lemma>] {
360360
var o: [ID: Unowned<Lemma>] = [:]
361-
for id in node.type {
362-
o[id] = lexicon.dictionary[id].map(Unowned.init)
361+
if isGraphNode {
362+
for id in node.type {
363+
o[id] = lexicon.dictionary[id].map(Unowned.init)
364+
}
365+
} else {
366+
for id in (parent?.node.type).or([]) {
367+
guard let node = lexicon.dictionary[id]?.children[name] else { continue }
368+
o[node.id] = Unowned(node)
369+
}
363370
}
364371
return o
365372
}

Sources/LexiconGenerators/List.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public extension Lexicon.Graph.JSON {
1212

1313
static let generators: OrderedDictionary<String, CodeGenerator.Type> = [
1414

15-
"Swift Library": SwiftLexicon.Generator.self,
15+
"Swift": SwiftLexicon.Generator.self,
1616

1717
"Swift Stand-Alone": SwiftStandAlone.Generator.self,
1818

0 commit comments

Comments
 (0)