Skip to content

Generate FoundationEssentials compatible code. - #874

Open
madsodgaard wants to merge 7 commits into
apple:mainfrom
madsodgaard:generated-foundation
Open

madsodgaard wants to merge 7 commits into
apple:mainfrom
madsodgaard:generated-foundation

Conversation

@madsodgaard

Copy link
Copy Markdown
Contributor

Motivation

Modifies the generator to generate code that can only depend on FoundationEssentials, instead of Full Essentials.

Modifications

  • Modified the file imports to support conditional imports
  • The Types.swift will now generate typealiases for Foundation:
#if canImport(FoundationEssentials)
package typealias FoundationURL = FoundationEssentials.URL
package typealias FoundationDate = FoundationEssentials.Date
#else
package typealias FoundationURL = Foundation.URL
package typealias FoundationDate = Foundation.Date
#endif

The alternative to this could be to introduce these types in swift-openapi-runtime. But that would mean the generated sources depend on a specific runtime version, which I guess is not OK?

Result

With this change and the recent changes to the runtime, you can now generate and run an entire OpenAPI client only using FoundationEssentials.

@simonjbeaumont

Copy link
Copy Markdown
Collaborator
  • The Types.swift will now generate typealiases for Foundation:
#if canImport(FoundationEssentials)
package typealias FoundationURL = FoundationEssentials.URL
package typealias FoundationDate = FoundationEssentials.Date
#else
package typealias FoundationURL = Foundation.URL
package typealias FoundationDate = Foundation.Date
#endif

How about generating this instead?

> #if canImport(FoundationEssentials)
> import struct FoundationEssentials.URL
> import struct FoundationEssentials.Date
> #else
> import struct Foundation.URL
> import struct Foundation.Date
> #endif

That way, the usage site for all these types remains the same, with plain URL and Date?

Additionally, our intermediate Swift representation tries to mimic the underlying AST mostly. I think, rather than augment the import statement type resulting in plain imports needing a new .always(...) wrapper, it might be better to express a compiler conditional block representation.

@madsodgaard

Copy link
Copy Markdown
Contributor Author

@simonjbeaumont yeah, the issue is that generally the generator wants to generate full type names, to prevent clashing with user types.

I chatted with @czechboy0 about this as well, and it's currently a task on me to write a forums thread about what the ESG recommends for code generators to do about the FoundationEssentials dance.

In my head, it would be most correct to move the aliases to the runtime package.

@simonjbeaumont

Copy link
Copy Markdown
Collaborator

In my head, it would be most correct to move the aliases to the runtime package.

I haven't given it much thought, but I'm not against having all the types needed by the generator being defined (or aliased) in the runtime library. Then, those definitions will be based on the traits specified in the runtime dependency.

the issue is that generally the generator wants to generate full type names, to prevent clashing with user types

Yeah, ofc 🤦! I remember this happening before and having to patch it.

Isn't this orthogonal though to how we spell the import statements? We can still import the type and then spell out the full qualified type at the use site: either Foundation.URL or FoundationEssentials.URL?

@czechboy0 what's the current thinking on the definitions being in the runtime lib? Any downsides?

@tkrajacic

Copy link
Copy Markdown

Is there any update on this front? APK size is still a major concern for Android, and I have created a HttpUrlConnection based transport for open-api-generator. So progressing here would be very welcome ❤️

@madsodgaard

madsodgaard commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor Author

@simonjbeaumont @czechboy0 Just wanted to revive this one. Any thoughts on what we discussed above?😄 I am still thinking we should move the aliases to the runtime lib, but wdyt?

We are still patching the generated sources manually afterwards, to remove Foundation.

@czechboy0
czechboy0 self-requested a review September 11, 2026 19:26
@czechboy0

Copy link
Copy Markdown
Contributor

Hi @madsodgaard, let me take another look, might just take a few more weeks.

@czechboy0 czechboy0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, @madsodgaard can you first resolve the conflicts from main? That'll allow me to review the code easier, thanks 🙏

@madsodgaard

Copy link
Copy Markdown
Contributor Author

@czechboy0 Should be resolved now

@czechboy0
czechboy0 self-requested a review September 15, 2026 14:29

@czechboy0 czechboy0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the fact that once we start generating these aliases, we can't remove them again without a major.

Could you start a thread on the Forums, asking the Foundation folks how code generators are supposed to be handling this Foundation/FoundationEssentials mismatch between platforms? What should cross-platform generated code that needs to fully qualify types look like? Please also tag @glbrntt as it might also be relevant for gRPC.

Thanks for your patience, I really want to make sure that we absolutely must introduce and maintain these typealiases.

@the-braveknight

Copy link
Copy Markdown

Any progress on this? Would love to see the generated code used FoundationEssentials where applicable.

@czechboy0

czechboy0 commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

@the-braveknight See my last message above. The solution isn't trivial, and before we commit to one, we need to make sure this is the approach the Foundation team recommends.

@the-braveknight

Copy link
Copy Markdown

I thought it was pretty straightforward, since grpc-swift-2, as well as other famous Swift on Server libraries have already moved in that direction, using FoundationEssentials if available, and falling back to full Foundation if not.

@the-braveknight

the-braveknight commented Sep 25, 2026 •

Copy link
Copy Markdown

@czechboy0

Copy link
Copy Markdown
Contributor

@the-braveknight Please take another look at this PR's code and the discussion above.

The issue is that the generated code uses fully qualified type names. That's the complex part, it's not clear how to do this efficiently and correctly, without introducing unnecessary typealiases.

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.

5 participants