Skip to content

Commit

Permalink
Merge pull request #3 from owowagency/feature/code-writing-options
Browse files Browse the repository at this point in the history
Added code writer options to allow configuring ACL level and bundles
  • Loading branch information
Obbut authored Oct 5, 2021
2 parents d74aba5 + bdc612d commit bbd6ce6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 71 deletions.
15 changes: 12 additions & 3 deletions Sources/owowgenerate-ios/Configuration/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct Configuration: Decodable {
var outputFiles: Set<String> {
return Set(tasks.compactMap { task -> [String]? in
switch task.type {
case .generateSwiftUIMapping, .generateNSLocalizedStringMapping, .generateSwiftUIMappingPublic, .generateNSLocalizedStringMappingPublic:
case .generateSwiftUIMapping, .generateNSLocalizedStringMapping:
return task.output.map { [$0] }
case .rewriteTranslationFiles:
return Array(stringsFiles.suffix(from: 1))
Expand All @@ -45,9 +45,7 @@ struct Configuration: Decodable {
struct Task: Decodable {
enum TaskType: String, Codable {
case generateSwiftUIMapping
case generateSwiftUIMappingPublic
case generateNSLocalizedStringMapping
case generateNSLocalizedStringMappingPublic
case rewriteTranslationFiles
case generateInputXcFileList
case generateOutputXcFileList
Expand All @@ -58,6 +56,9 @@ struct Task: Decodable {

/// The output file of the task.
var output: String?

/// Options for the task.
var options: TaskOptions?
}

enum CaseStyle: String, Codable {
Expand All @@ -73,3 +74,11 @@ enum CaseStyle: String, Codable {
}
}
}

struct TaskOptions: Codable {
/// The access level modifier (`internal`, `public`, etc) to use for generated code in the task.
var accessLevel: String? = nil

/// The `Bundle` to use in generated code. For example: `.module`, `Bundle(for: SomeClass.self)`, `Bundle(identifier: ...)`
var bundle: String? = nil
}
36 changes: 13 additions & 23 deletions Sources/owowgenerate-ios/Writers/NSLocalizedStringWriter.swift
Original file line number Diff line number Diff line change
@@ -1,58 +1,48 @@
fileprivate var isConstructingForLibrary = false

func makeLocalizedStringCode(strings: StringsCollection, isForLibrary: Bool) -> String {
if isForLibrary {
isConstructingForLibrary = isForLibrary
}

func makeLocalizedStringCode(strings: StringsCollection, accessLevel: String?, bundle: String?) -> String {
var writer = SwiftCodeWriter()
writer.addLine("import Foundation")
writer.addLine()

let extensionText = (isConstructingForLibrary ? "public " : "") + "enum Strings"
let aclPrefix = accessLevel.map { $0 + " " } ?? ""

writer.inBlock(extensionText) { writer in
writeStrings(strings: strings, writer: &writer)
writer.inBlock(aclPrefix + "enum Strings") { writer in
writeStrings(strings: strings, writer: &writer, aclPrefix: aclPrefix, bundle: bundle)
}

return writer.output
}

private func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWriter) {
private func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWriter, aclPrefix: String, bundle: String?) {
for (name, collection) in strings.subCollections.sorted(by: { $0.key < $1.key }) {
writer.addLine()

let variableName = name.camelCase(from: config.caseStyle, upper: false).swiftIdentifier
let typeName = (name.camelCase(from: config.caseStyle, upper: true)).swiftIdentifier

let line = (isConstructingForLibrary ? "public " : "") + "static var \(variableName): \(typeName).Type { \(typeName).self }"
let structBlock = (isConstructingForLibrary ? "public " : "") + "struct \(typeName)"
writer.addLine(aclPrefix + "static var \(variableName): \(typeName).Type { \(typeName).self }")

writer.addLine(line)
writer.inBlock(structBlock) { writer in
writeStrings(strings: collection, writer: &writer)
writer.inBlock(aclPrefix + "struct \(typeName)") { writer in
writeStrings(strings: collection, writer: &writer, aclPrefix: aclPrefix, bundle: bundle)
}
}

for key in strings.keys {
writer.addDocComment(key.comment)

let memberName = (key.key.split(separator: ".").last ?? "").camelCase(from: config.caseStyle, upper: false)
let getLocalizedString = "NSLocalizedString(\"\(key.key)\", comment: \(SwiftCodeWriter.makeStringLiteral(key.comment)))"

let bundleArgument = bundle.map { ", bundle: " + $0 } ?? ""
let getLocalizedString = "NSLocalizedString(\"\(key.key)\"\(bundleArgument), comment: \(SwiftCodeWriter.makeStringLiteral(key.comment)))"

if key.placeholders.isEmpty {
let line = (isConstructingForLibrary ? "public " : "") + "static var \(memberName): String { \(getLocalizedString) }"
writer.addLine(line)
writer.addLine(aclPrefix + "static var \(memberName): String { \(getLocalizedString) }")
} else {
let parameters = key.placeholders.enumerated().map { index, type in
"_ placeholder\(index): \(type.rawValue)"
}.joined(separator: ", ")

let parameterUsage = key.placeholders.indices.map { "placeholder\($0)" }.joined(separator: ", ")

let functionBlock = (isConstructingForLibrary ? "public " : "") + "static func \(memberName)(\(parameters)) -> String"

writer.inBlock(functionBlock) { writer in
writer.inBlock(aclPrefix + "static func \(memberName)(\(parameters)) -> String") { writer in
writer.addLine("let format = \(getLocalizedString)")
writer.addLine("return String(format: format, \(parameterUsage))")
}
Expand Down
57 changes: 18 additions & 39 deletions Sources/owowgenerate-ios/Writers/SwiftUICodeWriter.swift
Original file line number Diff line number Diff line change
@@ -1,65 +1,47 @@
fileprivate var shouldBePublic = false
fileprivate var isConstructingForLibrary = false

func makeSwiftUICode(strings: StringsCollection, isForLibrary: Bool) -> String {
if isForLibrary {
isConstructingForLibrary = isForLibrary
shouldBePublic = false
}

func makeSwiftUICode(strings: StringsCollection, accessLevel: String?, bundle: String?) -> String {
var writer = SwiftCodeWriter()
writer.addLine("import SwiftUI")
writer.addLine()

let extensionText = (isConstructingForLibrary ? "public " : "") + "extension SwiftUI.Text"
let aclPrefix = accessLevel.map { $0 + " " } ?? ""

writer.inBlock(extensionText) { writer in
writeStrings(strings: strings, writer: &writer)
writer.inBlock("extension SwiftUI.Text") { writer in
writeStrings(strings: strings, writer: &writer, aclPrefix: aclPrefix, bundle: bundle)
}

return writer.output
}

fileprivate func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWriter) {
fileprivate func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWriter, aclPrefix: String, bundle: String?) {
for (name, collection) in strings.subCollections.sorted(by: { $0.key < $1.key }) {
writer.addLine()

let variableName = name.camelCase(from: config.caseStyle, upper: false).swiftIdentifier
let typeName = (name.camelCase(from: config.caseStyle, upper: true) + "StringsNamespace").swiftIdentifier

if shouldBePublic && isConstructingForLibrary {
writer.addLine("public static var \(variableName): \(typeName).Type { \(typeName).self }")

writer.inBlock("public struct \(typeName)") { writer in
writeStrings(strings: collection, writer: &writer)
}
} else {
shouldBePublic = true
writer.addLine("static var \(variableName): \(typeName).Type { \(typeName).self }")

writer.inBlock("struct \(typeName)") { writer in
writeStrings(strings: collection, writer: &writer)
}
shouldBePublic = false
writer.addLine(aclPrefix + "static var \(variableName): \(typeName).Type { \(typeName).self }")

writer.inBlock(aclPrefix + "struct \(typeName)") { writer in
writeStrings(strings: collection, writer: &writer, aclPrefix: aclPrefix, bundle: bundle)
}
}

for key in strings.keys {
let memberName = (key.key.split(separator: ".").last ?? "").camelCase(from: config.caseStyle, upper: false)

if key.placeholders.isEmpty {
let additionalArguments: String
var additionalArguments = ""

if let bundle = bundle {
additionalArguments += ", bundle: \(bundle)"
}

if !key.comment.isEmpty {
additionalArguments = ", comment: \(SwiftCodeWriter.makeStringLiteral(key.comment))"
} else {
additionalArguments = ""
additionalArguments += ", comment: \(SwiftCodeWriter.makeStringLiteral(key.comment))"
}

writer.addDocComment(key.comment)

let line = (isConstructingForLibrary ? "public " : "") + "static var \(memberName): Text { Text(\"\(key.key)\"\(additionalArguments)) }"

writer.addLine(line)
writer.addLine(aclPrefix + "static var \(memberName): Text { Text(\"\(key.key)\"\(additionalArguments)) }")
} else {
let parameters = key.placeholders.enumerated().map { index, type in
"_ placeholder\(index): \(type.rawValue)"
Expand All @@ -68,10 +50,7 @@ fileprivate func writeStrings(strings: StringsCollection, writer: inout SwiftCod
let parameterUsage = key.placeholders.indices.map { "placeholder\($0)" }.joined(separator: ", ")

writer.addDocComment(key.comment)

let functionBlock = (isConstructingForLibrary ? "public " :"") + "static func \(memberName)(\(parameters)) -> Text"

writer.inBlock(functionBlock) { writer in
writer.inBlock(aclPrefix + "static func \(memberName)(\(parameters)) -> Text") { writer in
writer.addLine("let format = NSLocalizedString(\"\(key.key)\", comment: \(SwiftCodeWriter.makeStringLiteral(key.comment)))")
writer.addLine("let string = String(format: format, \(parameterUsage))")
writer.addLine("return Text(verbatim: string)")
Expand Down
16 changes: 10 additions & 6 deletions Sources/owowgenerate-ios/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ for task in config.tasks {

switch task.type {
case .generateSwiftUIMapping:
output = makeSwiftUICode(strings: strings, isForLibrary: false)
case .generateSwiftUIMappingPublic:
output = makeSwiftUICode(strings: strings, isForLibrary: true)
output = makeSwiftUICode(
strings: strings,
accessLevel: task.options?.accessLevel,
bundle: task.options?.bundle
)
case .generateNSLocalizedStringMapping:
output = makeLocalizedStringCode(strings: strings, isForLibrary: false)
case .generateNSLocalizedStringMappingPublic:
output = makeLocalizedStringCode(strings: strings, isForLibrary: true)
output = makeLocalizedStringCode(
strings: strings,
accessLevel: task.options?.accessLevel,
bundle: task.options?.bundle
)
case .rewriteTranslationFiles:
try! rewriteTranslationFiles(paths: config.stringsFiles)
continue
Expand Down

0 comments on commit bbd6ce6

Please sign in to comment.