WebAssembly / component-model

Repository for design and specification of the Component Model
Other
933 stars 79 forks source link

Allow imports to name implementations #222

Closed lukewagner closed 1 year ago

lukewagner commented 1 year ago

This PR extends the binary/text grammar of import names to allow imports to name not just interfaces, but also implementations. There are a number of ways to refer to an implementation (absolute URL, relative URL, precisely-versioned hierarchical name, version-ranged hierarchical name), so to keep things explicit (and avoid ad hoc string analysis) and support good bindings generation in the relevant cases, these cases are enumerated explicitly. (In the future, other cases could be added to importname as they present themselves.) Putting this semantic intent directly in the component binary allows it to be reliably interpreted by a variety of tools and runtimes, allowing better tooling interoperability than if a separate file or custom section was used.

This PR doesn't add the new import name cases to Wit yet because there are some interesting related workflow questions that I expect influence how this looks in Wit, suggesting this be a follow-up, once we agree on the target grammar/information. Also, the expectation is that, for the most part, folks won't need to write this in Wit, these implementation imports will be added late by the toolchain based on build-config files or import maps.

Unfortunately, there doesn't seem to be an "obvious" production we can simply reuse for describing version ranges, so, with a lot of help and ideas from @lann, a basic syntax is proposed built on semver that hopefully looks intuitive enough, but feedback welcome on this of course.

lann commented 1 year ago

After doing some more digging into semver constraints/ranges/comparators I want to point out a subtlety that wasn't obvious to me around matching against pre-release versions:

By a naive application of semver's precedence rules, the range >=1.0.0 <2.0.0 would match pre-release version 2.0.0-alpha.1, which seems surprising at best. Cargo/NPM avoid this with a subtle rule:

If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will only be allowed to satisfy req if at least one comparator with the same major.minor.patch also has a prerelease tag.

  • This means, for example (checking the typescript package with https://semver.npmjs.com/), for a pre-release version 5.0.0-dev:
  • these ranges do not match: >=4.0.0 <6.0.0, >=4.0.0-alpha <6.0.0-zeta
  • these ranges do match: >=5.0.0-alpha <6.0.0, >=4.0.0 <5.0.0-zeta
  • Another somewhat-surprising consequence of this rule is that * never matches any prerelease version

I'm not sure what action to take here beyond being aware of this in tooling implementations. Maybe it would be worthwhile to add a note along the lines of "interpretation of verrange is not specified here, but you should do what cargo/npm do wrt pre-release versions".

lukewagner commented 1 year ago

@lann Good to know! I see I really didn't even say anything about how to interpret the version ranges, so I added a paragraph on semver here.

lukewagner commented 1 year ago

Looks like no disagreement on the PR, so almost ready to merge. However, one more important use case came up recently in the context of registries (and, concretely, sharing component contents via OCI Registries) where one wants to name an implementation purely via its content hash without any additional URL or registry name (and where forcing a URL or registry name would just add a needless hoop to jump through). Thus, this commit adds a 5th implementation import case that has integrity but no URL or registry name. This is a relatively small addition, so I'll wait for comments until the end of the week to merge.