Scaffold v1.0.0

This commit is contained in:
T. R. Bernstein
2026-04-17 01:08:29 +02:00
commit b49d642dfd
22 changed files with 983 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
import Foundation
struct SwiftCodeGenerator {
private let fileContentReader: FileContentReader
private let indentationUnit: String
init(
fileContentReader: FileContentReader = FileContentReader(),
indentationUnit: String = " "
) {
self.fileContentReader = fileContentReader
self.indentationUnit = indentationUnit
}
func generate(from rootNamespace: NamespaceNode) throws -> String {
generatedFileBanner() + (try renderNamespace(rootNamespace, depth: 0))
}
}
private extension SwiftCodeGenerator {
func generatedFileBanner() -> String {
"""
// Generated by the Embedder plugin from the "Static Inline" directory.
// Any manual changes will be overwritten on the next build.
""" + "\n"
}
func renderNamespace(_ namespace: NamespaceNode, depth: Int) throws -> String {
let openingLine = namespaceOpeningLine(for: namespace, depth: depth)
let bodyLines = try renderBody(of: namespace, depth: depth + 1)
let closingLine = namespaceClosingLine(depth: depth)
return openingLine + bodyLines + closingLine
}
func namespaceOpeningLine(for namespace: NamespaceNode, depth: Int) -> String {
"\(indent(depth: depth))enum \(namespace.name) {\n"
}
func namespaceClosingLine(depth: Int) -> String {
"\(indent(depth: depth))}\n"
}
func renderBody(of namespace: NamespaceNode, depth: Int) throws -> String {
let fileDeclarations = try namespace.files.map { try renderFileDeclaration($0, depth: depth) }
let nestedNamespaces = try namespace.subNamespaces.map { try renderNamespace($0, depth: depth) }
return joinWithBlankLines(fileDeclarations + nestedNamespaces)
}
func renderFileDeclaration(_ file: EmbeddableFile, depth: Int) throws -> String {
let propertyName = IdentifierSanitizer.propertyName(fromFilename: file.filename)
let literal = try renderStringLiteral(for: file, baseIndent: indent(depth: depth))
return "\(indent(depth: depth))static let \(propertyName): String = \(literal)\n"
}
func renderStringLiteral(for file: EmbeddableFile, baseIndent: String) throws -> String {
let content = try fileContentReader.readTextContent(of: file)
let rawLiteral = StringLiteralEscaper.rawTripleQuotedLiteral(from: content)
return indentContinuationLines(of: rawLiteral, by: baseIndent)
}
func indentContinuationLines(of literal: String, by baseIndent: String) -> String {
let lines = literal.components(separatedBy: "\n")
guard lines.count > 1 else { return literal }
let firstLine = lines[0]
let continuationLines = lines.dropFirst().map { "\(baseIndent)\($0)" }
return ([firstLine] + continuationLines).joined(separator: "\n")
}
func joinWithBlankLines(_ declarations: [String]) -> String {
declarations.joined(separator: "\n")
}
func indent(depth: Int) -> String {
String(repeating: indentationUnit, count: depth)
}
}