Skip to content

Conversation

@rcancro
Copy link

@rcancro rcancro commented Sep 6, 2024

In the given schema file, we can see the class board_activity references itself:

{
    "id": "board_activity.json",
    "title": "board_activity",
    "description": "Schema definition of a BoardActivity",
    "$schema": "http://json-schema.org/schema#",
    "type": "object",
    "properties": {
      "ref_board_activity": { "$ref": "board_activity.json" },
    },
}

This causes multiple BoardActivity imports in BoardActivity.m. The issue is in ObjCIR.Root.imports renderImplementation method. This is how the imports are being generated:

case .imports(let classNames, let myName, _):
    return [classNames.union(Set([myName]))
        .sorted()
        .map { $0.trimmingCharacters(in: .whitespaces) }
        .map { ObjCIR.fileImportStmt($0, headerPrefix: params[GenerationParameterType.headerPrefix]) }
        .joined(separator: "\n")]

Using the schema above, classNames would include “BoardActivity “. Note the space. myName would be ”BoardActivity”. Note the lack of space.

These two get unioned together in a set. The result is ["BoardActivity ", "BoardActivity"]. We sort this set, then remove any trailing spaces. But at this point we are an array, and we now have two duplicate entries in our array: ["BoardActivity", "BoardActivity"]. This leads plank to render #import "BoardActivity.h" twice in our implementation file.

A solution would be to trim these strings BEFORE the union:

case .imports(let classNames, let myName, _):
    let strippedClassNames = Set(classNames.map { $0.trimmingCharacters(in: .whitespaces) })
    return [strippedClassNames.union(Set([myName.trimmingCharacters(in: .whitespaces)]))
        .sorted()
        .map { ObjCIR.fileImportStmt($0, headerPrefix: params[GenerationParameterType.headerPrefix]) }
        .joined(separator: "\n")]

I created strippedClassNames which holds the trimmed classNames. This gets unioned that with the stripped version of myName to get the list of imports. Now we end up with the array only have one entry ["BoardActivity"].

Note: I also made a change in ObjectiveCNSCodingExtension.swift because the compiler was telling me that the return value was too complicated for it to figure out.

In the given schema file, we can see the class references itself:
```
{
    "id": "board_activity.json",
    "title": "board_activity",
    "description": "Schema definition of a BoardActivity",
    "$schema": "http://json-schema.org/schema#",
    "type": "object",
    "properties": {
      "ref_board_activity": { "$ref": "board_activity.json" },
    },
}
```

This would cause multiple `BoardActivity` imports in `BoardActivity.m`. This was caused by calling `ObjCIR.Root.imports` `renderImplementation` method. This is how the imports were being generated:
```
case .imports(let classNames, let myName, _):
    return [classNames.union(Set([myName]))
        .sorted()
        .map { $0.trimmingCharacters(in: .whitespaces) }
        .map { ObjCIR.fileImportStmt($0, headerPrefix: params[GenerationParameterType.headerPrefix]) }
        .joined(separator: "\n")]
```
Using the schema above, `classNames` would include `“BoardActivity “`. Note the space. `myName` would be `”BoardActivity”`. Note the lack of space.

These two get unioned together in a set. The result is  `[“BoardActivity ", "BoardActivity”]`. We sort this set, then remove any trailing spaces. But at this point it is too late! We are no longer a set, we are an array which can have multiple of equivalent objects. At this point our array is `[“BoardActivity", "BoardActivity”]`. This leads to duplicate import statements.

A solution would be to trim these strings BEFORE the union:
```
case .imports(let classNames, let myName, _):
    let strippedClassNames = Set(classNames.map { $0.trimmingCharacters(in: .whitespaces) })
    return [strippedClassNames.union(Set([myName.trimmingCharacters(in: .whitespaces)]))
        .sorted()
        .map { ObjCIR.fileImportStmt($0, headerPrefix: params[GenerationParameterType.headerPrefix]) }
        .joined(separator: "\n")]
```
I created `strippedClassNames` which holds the trimmed `classNames`. This gets unioned that with the stripped version of `myName` to get the list of imports. Now we end up with the array only have one entry `[“BoardActivity”]`.

Note: I also made a change in `ObjectiveCNSCodingExtension.swift` because the compiler was telling me that the return value was too complicated for it to figure out.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants