Repository: CreateAPI/CreateAPI (swift)

Issue:
Change `rename.properties` to use schema names
I observe in [this comment](https://github.com/CreateAPI/CreateAPI/pull/106#discussion_r938926493) that `rename.properties` requires the format of the post-processed entity name that will be attached to the final entity.

## Example

The following config:
```yaml
Pet:
  properties:
    example_name:
      type: string
    enabled:
      type: boolean
    source_url:
      type: String
```

will result in the entity:
```swift
struct Pet {
    var exampleName: String
    var isEnabled: String // due to useSwiftyPropertyNames
    var sourceURL: String // due to isReplacingCommonAcronyms
}
```

When a developer uses `rename.properties`, they are required to use the final processed entity name for the key and the value is a literal translation [1], no processing is done on the renamed property. Additionally, the developer has to know what acronyms are used and the states of the `pluralizeProperties`, and `useSwiftyPropertyNames`. This can cause a lot of problems during renaming and I omit examples of mixture of these properties because it's pretty straightforward.

```yaml
rename:
  properties:
    Pet.isEnabled: somethingElse
    Pet.sourceURL: another_url # will literally become `another_url` on the entity
```

## Change
To be consistent with `include/exclude` and to be more clear with how the config should be created, we should instead change `rename.properties` to use the schema object names for keys and values.

```yaml
rename:
  properties:
    Pet.enabled: something_else
    Pet.source_url: another_url
```

would result in the entity:
```swift
struct Pet {
    var exampleName: String
    var somethingElse: String
    var anotherURL: String
}
```

---

- [1] I don't think that literal translations should be an intended use of `rename.properties`. If a developer really _really_ wanted to break their own convention we could implement some kind of literal renaming option that ignores the naming processing steps. I think a comment would be very clear and declarative, but I don't know how the YAML would parse that at the moment:

```yaml
rename:
  properties:
    Pet.enabled: something_else
    Pet.source_url: another_url # literal
```

Pull request:
- Closes https://github.com/CreateAPI/CreateAPI/issues/112

Renames property names prior to processing, meaning that they will respect the schema name instead of the final Swift name. Updates the edge case test for proper schema renaming and some other tests that renamed _to_ a Swifty name.

Patch:
diff --git a/Docs/ConfigOptions.md b/Docs/ConfigOptions.md
index 8f613bb3..2ac854e5 100644
--- a/Docs/ConfigOptions.md
+++ b/Docs/ConfigOptions.md
@@ -759,15 +759,21 @@ Options used to configure detailed renaming rules for all aspects of the generat
 **Type:** [String: String]<br />
 **Default:** `[:]`
 
-Rename rules for properties specific to a given type, or all properties with a matching name.
+Rename schema properties prior to processing. Rules can apply to all properties or to
+properties of a specific entity.
+
+<details>
+<summary>Examples</summary>
 
 ```yaml
 rename:
   properties:
-    name: firstName # renames any property called 'name' to 'firstName'
-    SimpleUser.name: firstName # renames only the 'name' property on the 'SimpleUser' entity
+    favorite_food: food # renames any schema property called 'favorite_food` to food
+    User.first_name: name # renames only the 'first_name` schema property on the `User` entity
 ```
 
+</details>
+
 <br/>
 
 ## rename.parameters
diff --git a/Sources/CreateAPI/Generator/Generator+Schemas.swift b/Sources/CreateAPI/Generator/Generator+Schemas.swift
index 6dab0d46..b6a29aca 100644
--- a/Sources/CreateAPI/Generator/Generator+Schemas.swift
+++ b/Sources/CreateAPI/Generator/Generator+Schemas.swift
@@ -670,7 +670,18 @@ extension Generator {
     // MARK: - Property
 
     func makeProperty(key: String, schema: JSONSchema, isRequired: Bool, in context: Context, isInlined: Bool? = nil) throws -> Property {
-        let propertyName: PropertyName
+        func rename(key: String) -> String {
+            if !options.rename.properties.isEmpty {
+                let names = context.parents.map { $0.name.rawValue } + [key]
+                for i in names.indices {
+                    if let name = options.rename.properties[names[i...].joined(separator: ".")] {
+                        return name
+                    }
+                }
+            }
+            
+            return key
+        }
 
         /**
         Strips the parent name of enum cases within objects that are `oneOf` / `allOf` / `anyOf` of 
@@ -703,35 +714,22 @@ extension Generator {
         ``` 
 
         */
+        
+        var propertyIdentifier = key
+        
         if options.entities.stripParentNameInNestedObjects,
             case .reference(let ref, _) = schema.value,
             let parentName = context.parents.first?.name.rawValue,
             let ownName = ref.name {
             let prefix = ownName.commonPrefix(with: parentName)
 
-            propertyName = makePropertyName(String(ownName.dropFirst(prefix.count)))
-        } else {
-            propertyName = makePropertyName(key)
-        }
-
-        func makeName(for name: PropertyName, type: TypeIdentifier? = nil) -> PropertyName {
-            if !options.rename.properties.isEmpty {
-                let names = context.parents.map { $0.name.rawValue } + [name.rawValue]
-                for i in names.indices {
-                    if let name = options.rename.properties[names[i...].joined(separator: ".")] {
-                        return PropertyName(name)
-                    }
-                }
-            }
-            if let type = type, options.useSwiftyPropertyNames && type.isBool {
-                return name.asBoolean(options)
-            }
-            return name
+            propertyIdentifier = String(ownName.dropFirst(prefix.count))
         }
+        
+        let propertyName = makePropertyName(rename(key: propertyIdentifier))
 
         func property(type: TypeIdentifier, info: JSONSchemaContext?, nested: Declaration? = nil) -> Property {
             let nullable = info?.nullable ?? false
-            let name = makeName(for: propertyName, type: type)
             let isOptional = !isRequired || nullable
             var type = type
             if context.isPatch && isOptional && options.paths.makeOptionalPatchParametersDoubleOptional {
@@ -743,7 +741,21 @@ extension Generator {
                     defaultValue = (info?.defaultValue?.value as? Bool).map { $0 ? "true" : "false" }
                 }
             }
-            return Property(name: name, type: type, isOptional: isOptional, key: key, defaultValue: defaultValue, metadata: .init(info), nested: nested, isInlined: isInlined)
+            
+            var propertyName = propertyName
+            
+            if type.isBool && options.useSwiftyPropertyNames {
+                propertyName = propertyName.asBoolean(options)
+            }
+            
+            return Property(name: propertyName,
+                            type: type,
+                            isOptional: isOptional,
+                            key: key,
+                            defaultValue: defaultValue,
+                            metadata: .init(info),
+                            nested: nested,
+                            isInlined: isInlined)
         }
 
         // TOOD: This can be done faster for primitive types (no makeTypeName)
diff --git a/Sources/CreateOptions/ConfigOptions.swift b/Sources/CreateOptions/ConfigOptions.swift
index 7d72d92f..3552393a 100644
--- a/Sources/CreateOptions/ConfigOptions.swift
+++ b/Sources/CreateOptions/ConfigOptions.swift
@@ -490,14 +490,20 @@ public struct ConfigOptions: ParsableConfiguration {
     public struct Rename: ParsableConfiguration {
         public init() { }
 
-        /// Rename rules for properties specific to a given type, or all properties with a matching name.
+        /// Rename schema properties prior to processing. Rules can apply to all properties or to
+        /// properties of a specific entity.
+        ///
+        /// <details>
+        /// <summary>Examples</summary>
         ///
         /// ```yaml
         /// rename:
         ///   properties:
-        ///     name: firstName # renames any property called 'name' to 'firstName'
-        ///     SimpleUser.name: firstName # renames only the 'name' property on the 'SimpleUser' entity
+        ///     favorite_food: food # renames any schema property called 'favorite_food` to food
+        ///     User.first_name: name # renames only the 'first_name` schema property on the `User` entity
         /// ```
+        ///
+        /// </details>
         @Option public var properties: [String: String] = [:]
 
         /// Rename query parameters


Test patch:
diff --git a/Tests/CreateAPITests/GenerateOptionsTests.swift b/Tests/CreateAPITests/GenerateOptionsTests.swift
index 1ee754d8..4a533b31 100644
--- a/Tests/CreateAPITests/GenerateOptionsTests.swift
+++ b/Tests/CreateAPITests/GenerateOptionsTests.swift
@@ -341,7 +341,7 @@ final class GenerateOptionsTests: GenerateTestCase {
                     id: identifier
                     Category.name: title
                     Pet.status: state
-                    complete: isDone
+                    complete: done
             """
         )
     }
@@ -387,7 +387,7 @@ final class GenerateOptionsTests: GenerateTestCase {
             {
                 "rename": {
                     "properties": {
-                        "ContainerA.Child.Child.renameMe": "onlyItRenamed"
+                        "ContainerA.Child.Child.rename-me": "onlyItRenamed"
                     },
                     "entities": {
                         "ApiResponse": "APIResponse",
@@ -532,7 +532,7 @@ final class GenerateOptionsTests: GenerateTestCase {
                 - Store.pets
             rename:
                 properties:
-                    Pet.id: notID
+                    Pet.id: not_id
                     Pet.name: id
             """
         )