Skip to content

Commit f231ccd

Browse files
committed
WIP - update to support editions
updates Update Generator.swift Signed-off-by: Michael Rebello <[email protected]>
1 parent fa8485e commit f231ccd

File tree

8 files changed

+136
-205
lines changed

8 files changed

+136
-205
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ let package = Package(
121121
name: "ConnectMocksPlugin",
122122
dependencies: [
123123
"ConnectPluginUtilities",
124+
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
124125
.product(name: "SwiftProtobufPluginLibrary", package: "swift-protobuf"),
125126
],
126127
path: "Plugins/ConnectMocksPlugin"

Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,35 @@ import ConnectPluginUtilities
1616
import Foundation
1717
import SwiftProtobufPluginLibrary
1818

19-
/// Responsible for generating services and RPCs that are compatible with the Connect library.
19+
/// Responsible for generating mocks that are compatible with generated Connect services.
20+
@main
2021
final class ConnectMockGenerator: Generator {
21-
private let propertyVisibility: String
22-
private let typeVisibility: String
22+
private var propertyVisibility = ""
23+
private var typeVisibility = ""
2324

24-
required init(_ descriptor: FileDescriptor, options: GeneratorOptions) {
25-
switch options.visibility {
25+
override var outputFileExtension: String {
26+
return ".mock.swift"
27+
}
28+
29+
override func printContent(for descriptor: FileDescriptor) {
30+
super.printContent(for: descriptor)
31+
32+
switch self.options.visibility {
2633
case .internal:
2734
self.propertyVisibility = "internal"
2835
self.typeVisibility = "internal"
2936
case .public:
3037
self.propertyVisibility = "public"
3138
self.typeVisibility = "open"
3239
}
33-
super.init(descriptor, options: options)
34-
self.printContent()
35-
}
36-
37-
private func printContent() {
38-
self.printFilePreamble()
3940

4041
if self.options.generateCallbackMethods {
4142
self.printModuleImports(adding: ["Combine", "ConnectMocks"])
4243
} else {
4344
self.printModuleImports(adding: ["ConnectMocks"])
4445
}
4546

46-
for service in self.descriptor.services {
47+
for service in self.services {
4748
self.printLine()
4849
self.printMockService(service)
4950
}

Plugins/ConnectMocksPlugin/main.swift

Lines changed: 0 additions & 19 deletions
This file was deleted.

Plugins/ConnectPluginUtilities/Generator.swift

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,49 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import SwiftProtobuf
1516
import SwiftProtobufPluginLibrary
1617

17-
/// Base generator class that can be used to output a file from a Protobuf file descriptor.
18+
private struct GeneratorError: Swift.Error {
19+
let message: String
20+
}
21+
22+
/// Base generator class that can be used to output files from Protobuf file descriptors.
23+
///
24+
/// Subclasses must be annotated with `@main` to be properly invoked at runtime.
1825
open class Generator {
19-
private var printer = CodePrinter(indent: " ".unicodeScalars)
26+
private var printer = SwiftProtobufPluginLibrary.CodePrinter()
2027

21-
public let descriptor: FileDescriptor
22-
public let namer: SwiftProtobufNamer
23-
public let options: GeneratorOptions
28+
/// Used for producing type names when generating code.
29+
public private(set) var namer = SwiftProtobufPluginLibrary.SwiftProtobufNamer()
30+
/// List of Swift module dependencies required by the current Protobuf file.
31+
public private(set) var neededModules = [String]()
32+
/// Options to use when generating code.
33+
public private(set) var options = GeneratorOptions.empty()
34+
/// List of services specified in the current file.
35+
public private(set) var services = [SwiftProtobufPluginLibrary.ServiceDescriptor]()
2436

25-
public var output: String {
26-
return self.printer.content
37+
// MARK: - Overridable
38+
39+
/// File extension to use for generated file names.
40+
open var outputFileExtension: String {
41+
return ".connect.swift"
2742
}
2843

29-
public required init(_ descriptor: FileDescriptor, options: GeneratorOptions) {
30-
self.descriptor = descriptor
31-
self.options = options
32-
self.namer = SwiftProtobufNamer(
33-
currentFile: descriptor,
34-
protoFileToModuleMappings: options.protoToModuleMappings
35-
)
44+
/// Initializer required by `SwiftProtobufPluginLibrary.CodeGenerator`.
45+
public required init() {}
46+
47+
/// Should be overridden by subclasses to write output for a given file descriptor.
48+
/// Subclasses should call `super` before producing their own outputs.
49+
/// May be called multiple times (once per file descriptor) over the lifetime of this class.
50+
///
51+
/// - parameter descriptor: The file descriptor for which to generate code.
52+
open func printContent(for descriptor: SwiftProtobufPluginLibrary.FileDescriptor) {
53+
self.printLine("// Code generated by protoc-gen-connect-swift. DO NOT EDIT.")
54+
self.printLine("//")
55+
self.printLine("// Source: \(descriptor.name)")
56+
self.printLine("//")
57+
self.printLine()
3658
}
3759

3860
// MARK: - Output helpers
@@ -58,30 +80,75 @@ open class Generator {
5880
self.printer.print("\n")
5981
}
6082

61-
public func printCommentsIfNeeded(for entity: ProvidesSourceCodeLocation) {
83+
public func printCommentsIfNeeded(
84+
for entity: SwiftProtobufPluginLibrary.ProvidesSourceCodeLocation
85+
) {
6286
let comments = entity.protoSourceComments().trimmingCharacters(in: .whitespacesAndNewlines)
6387
if !comments.isEmpty {
6488
self.printLine(comments)
6589
}
6690
}
6791

68-
public func printFilePreamble() {
69-
self.printLine("// Code generated by protoc-gen-connect-swift. DO NOT EDIT.")
70-
self.printLine("//")
71-
self.printLine("// Source: \(self.descriptor.name)")
72-
self.printLine("//")
73-
self.printLine()
74-
}
75-
7692
public func printModuleImports(adding additional: [String] = []) {
7793
let defaults = ["Connect", "Foundation", self.options.swiftProtobufModuleName]
7894
let extraOptionImports = self.options.extraModuleImports
79-
let mappings = self.options.protoToModuleMappings
80-
.neededModules(forFile: self.descriptor) ?? []
81-
let allImports = (defaults + mappings + extraOptionImports + additional).sorted()
82-
95+
let allImports = (defaults + self.neededModules + extraOptionImports + additional).sorted()
8396
for module in allImports {
8497
self.printLine("import \(module)")
8598
}
8699
}
87100
}
101+
102+
extension Generator: SwiftProtobufPluginLibrary.CodeGenerator {
103+
private func resetAndPrintFile(
104+
for descriptor: SwiftProtobufPluginLibrary.FileDescriptor, with options: GeneratorOptions
105+
) -> String {
106+
self.namer = SwiftProtobufPluginLibrary.SwiftProtobufNamer(
107+
currentFile: descriptor,
108+
protoFileToModuleMappings: self.options.protoToModuleMappings
109+
)
110+
self.neededModules = self.options.protoToModuleMappings
111+
.neededModules(forFile: descriptor) ?? []
112+
self.options = options
113+
self.services = descriptor.services
114+
self.printer = SwiftProtobufPluginLibrary.CodePrinter(indent: " ".unicodeScalars)
115+
self.printContent(for: descriptor)
116+
return self.printer.content
117+
}
118+
119+
public func generate(
120+
files: [SwiftProtobufPluginLibrary.FileDescriptor],
121+
parameter: any SwiftProtobufPluginLibrary.CodeGeneratorParameter,
122+
protoCompilerContext _: any SwiftProtobufPluginLibrary.ProtoCompilerContext,
123+
generatorOutputs: any SwiftProtobufPluginLibrary.GeneratorOutputs
124+
) throws {
125+
let options = try GeneratorOptions(commandLineParameters: parameter)
126+
guard options.generateAsyncMethods || options.generateCallbackMethods else {
127+
throw GeneratorError(
128+
message: "Either async methods or callback methods must be enabled"
129+
)
130+
}
131+
132+
for descriptor in files where !descriptor.services.isEmpty {
133+
try generatorOutputs.add(
134+
fileName: FilePathComponents(path: descriptor.name).outputFilePath(
135+
withExtension: self.outputFileExtension, using: options.fileNaming
136+
),
137+
contents: self.resetAndPrintFile(for: descriptor, with: options)
138+
)
139+
}
140+
}
141+
142+
public var supportedEditionRange: ClosedRange<SwiftProtobuf.Google_Protobuf_Edition> {
143+
return SwiftProtobufPluginLibrary.DescriptorSet.bundledEditionsSupport
144+
}
145+
146+
public var supportedFeatures: [
147+
SwiftProtobufPluginLibrary.Google_Protobuf_Compiler_CodeGeneratorResponse.Feature
148+
] {
149+
return [
150+
.proto3Optional,
151+
.supportsEditions,
152+
]
153+
}
154+
}

Plugins/ConnectPluginUtilities/GeneratorOptions.swift

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -42,33 +42,6 @@ private enum CommandLineParameter: String {
4242
}
4343
}
4444
}
45-
46-
static func parse(commandLineParameters: String) throws -> [(key: Self, value: String)] {
47-
return try commandLineParameters
48-
.components(separatedBy: ",")
49-
.compactMap { parameter in
50-
if parameter.isEmpty {
51-
return nil
52-
}
53-
54-
guard let index = parameter.firstIndex(of: "=") else {
55-
throw Error.unknownParameter(string: parameter)
56-
}
57-
58-
let rawKey = parameter[..<index].trimmingCharacters(in: .whitespacesAndNewlines)
59-
guard let key = Self(rawValue: rawKey) else {
60-
throw Error.unknownParameter(string: parameter)
61-
}
62-
63-
let value = parameter[parameter.index(after: index)...]
64-
.trimmingCharacters(in: .whitespacesAndNewlines)
65-
if value.isEmpty {
66-
return nil
67-
}
68-
69-
return (key, value)
70-
}
71-
}
7245
}
7346

7447
/// A set of options that are used to customize generator outputs.
@@ -94,18 +67,23 @@ public struct GeneratorOptions {
9467
case `public` = "Public"
9568
}
9669

70+
public static func empty() -> Self {
71+
return .init()
72+
}
73+
}
74+
75+
extension GeneratorOptions {
9776
/// Initializes a set of generator options from the raw string representation of command line
9877
/// parameters (e.g., "Visibility=Internal,KeepMethodCasing=true").
9978
///
100-
/// Handles trimming whitespace, and some parameters may be specified multiple times.
101-
///
102-
/// - parameter commandLineParameters: The raw CLI parameters.
103-
public init(commandLineParameters: String) throws {
104-
let parsedParameters = try CommandLineParameter.parse(
105-
commandLineParameters: commandLineParameters
106-
)
107-
for (key, rawValue) in parsedParameters {
108-
switch key {
79+
/// - parameter commandLineParameters: The CLI parameters.
80+
public init(commandLineParameters: SwiftProtobufPluginLibrary.CodeGeneratorParameter) throws {
81+
for (key, rawValue) in commandLineParameters.parsedPairs {
82+
guard let parsedKey = CommandLineParameter(rawValue: key) else {
83+
throw CommandLineParameter.Error.unknownParameter(string: key)
84+
}
85+
86+
switch parsedKey {
10987
case .extraModuleImports:
11088
self.extraModuleImports.append(rawValue)
11189
continue
@@ -145,9 +123,7 @@ public struct GeneratorOptions {
145123
self.protoToModuleMappings = try ProtoFileToModuleMappings(path: rawValue)
146124
continue
147125
} catch let error {
148-
throw CommandLineParameter.Error.deserializationError(
149-
key: key.rawValue, error: error
150-
)
126+
throw CommandLineParameter.Error.deserializationError(key: key, error: error)
151127
}
152128

153129
case .swiftProtobufModuleName:
@@ -161,10 +137,7 @@ public struct GeneratorOptions {
161137
}
162138
}
163139

164-
throw CommandLineParameter.Error.invalidParameterValue(
165-
key: key.rawValue,
166-
value: rawValue
167-
)
140+
throw CommandLineParameter.Error.invalidParameterValue(key: key, value: rawValue)
168141
}
169142
}
170143
}

Plugins/ConnectPluginUtilities/MainGeneratorFunction.swift

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)