Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicitly order browser releases #21124

Open
8 tasks
ddbeck opened this issue Oct 30, 2023 · 1 comment
Open
8 tasks

Explicitly order browser releases #21124

ddbeck opened this issue Oct 30, 2023 · 1 comment
Labels
enhancement 🥇 Nice to have features.

Comments

@ddbeck
Copy link
Collaborator

ddbeck commented Oct 30, 2023

What would you like to see added to BCD?

Summary

The browsers schema ought to use an explicitly ordered array instead of an object for releases; release keys ought to move to the value of a version key on release objects. If you only have time to read one thing, look at the Data before and after section.

Problem description

BCD doesn’t explicitly provide ordering information about browser releases, thus each consumer of BCD must make fresh decisions about how to parse, order, and compare version numbers found in BCD.

Presently, BCD communicates the order of browser releases by implication: the insertion order of keys in releases corresponds to ordering releases by release_date, while undated future releases follow dated releases. The ordering is, since version v4.1.1, stable between releases but undocumented.

Unfortunately, evidence suggests that consumers of BCD should not rely on this implicit order:

  • Before the removal of some Safari releases from BCD, releases had a potentially ambiguous order (for example, Safari 7 and 6.1 had the same release date). While this is not true today, the BCD documentation makes no guarantees that this will continue to be true in the future (nor is it obvious that BCD could guarantee this).

  • BCD’s own tooling does not use this order to compare versions. Instead, it uses a library, compare-versions, to do string comparisons according to Semantic Versioning (despite the knowledge that no major browser actually uses SemVer for versioning).

Further complications:

  • Relying on JavaScript behaviors for JSON data: In the contemporary ECMAScript specification, operations on object keys have a well-defined order, but BCD’s release date schema predates many of these changes to the specification. It’s unclear whether BCD is relying on that behavior to impart meaning about its data.

  • An undisclosed dependency: Even though it’s available as an npm package, BCD has always been something of a dumb JSON object and BCD’s consumers might reasonably consume the data outside of JavaScript. The JSON specification defines objects as being explicitly unordered. Non-JavaScript consumers of BCD may not have a convenient way to consume BCD’s JSON in the same order that JavaScript’s operations on object keys would provide, or might not have access to an equivalent to compare-versions.

Taken together, BCD’s order of browser releases is largely undefined and left as an exercise to the data consumer. Speaking as a consumer, some of these things (e.g., the hidden dependency for compare-versions) are really, really annoying.

Proposal

To fix this problem, I propose to modify the schema to represent releases as an array of release objects. That is:

  1. The current releases object would become an array, with each member of the array being a release object (i.e., the values of the existing version keys).
  2. The existing version keys would become the value to a new release object key, version.

Data before and after

An existing browser object looks something like this:

{
  "browsers": {
    "example": {
      "name": "Example Browser",
      "type": "desktop",
      "accepts_flags": false,
      "accepts_webextensions": false,
      "releases": {
        "1": {
          "release_date": "2023-08-28",
          "release_notes": "https://example.com/relnote/1",
          "status": "retired",
          "engine_version": "1"
        },
        "2": {
          "release_date": "2023-09-28",
          "release_notes": "https://example.com/relnote/2",
          "status": "retired",
          "engine_version": "2"
        },
        "3": {
          "release_date": "2023-10-28",
          "release_notes": "https://example.com/relnote/3",
          "status": "current",
          "engine_version": "3"
        },
        "4": {
          "release_notes": "https://example.com/relnote/4",
          "status": "beta",
          "engine_version": "4"
        }
      }
    }
  }
}

Under this proposal, a browser object would look like this:

{
  "browsers": {
    "example": {
      "name": "Example Browser",
      "type": "desktop",
      "accepts_flags": false,
      "accepts_webextensions": false,
      "releases": [
        {
          "version": "1",
          "release_date": "2023-08-28",
          "release_notes": "https://example.com/relnote/1",
          "status": "retired",
          "engine_version": "1"
        },
        {
          "version": "2",
          "release_date": "2023-09-28",
          "release_notes": "https://example.com/relnote/2",
          "status": "retired",
          "engine_version": "2"
        },
        {
          "version": "3",
          "release_date": "2023-10-28",
          "release_notes": "https://example.com/relnote/3",
          "status": "current",
          "engine_version": "3"
        },
        {
          "version": "4",
          "release_notes": "https://example.com/relnote/4",
          "status": "beta",
          "engine_version": "4"
        }
      ]
    }
  }
}

Costs and benefits of this approach

This approach has several benefits:

  • It’s more explicit than the status quo: arrays are, by definition, ordered. Documentation would only need to communicate that the releases are in ascending order.

  • It’s less complicated to consume than the status quo. For instance, if you wish to determine whether a release is included in the range defined by a support statement’s version_added and version_removed values, then you can determine this without transforming a release object into an array first or comparing version strings: you’re just three findIndex()es away from this information.

  • Fewer dependencies and less knowledge are required than the status quo. For instance, you don’t have to know anything about SemVer or version string conventions to determine whether one release is before or after another. You would have to know that bigger indices are later versions.

  • For consumers that like the status quo, there exist straightforward paths to getting the new data into the old structure. For example:

    data.browsers.example.releases.reduce((accumulator, release) => {
      const { version, ...rest } = release;
      return { ...accumulator, [version]: rest }
    }, {});

This approach does have two significant costs:

  • This is breaking schema change. Existing consumers of BCD will have to adapt to the new schema and we’ll have to create documentation to address the upgrade path.
  • This will require some changes to the existing linters and browser release update scripts. I don't know how pervasive these changes are.

Alternatives considered

I considered a couple of other ways to deal with this:

  • Document the ordered-by-insertion practice. This has the benefit of avoiding most schema or tooling changes, but leaves some issues (ordering outside of JavaScript, the availability of compare-versions, etc.) in the hands of consumers. This also requires several decisions to be made which might be subject to considerable debate (e.g., whether to document browser’s versioning schemes or to bless SemVer as a method for comparing version strings).

  • Do nothing. This is not often a subject of complaints. This has the benefit of being the least amount of work, but leaves all of the problems in place.

Supporting materials

Task list

Adopting this proposal will require the following tasks (and probably several more unknown to me):

  • Get feedback from MDN, caniuse
  • Update the schema file
  • Write a data migration script
  • Update the schema documentation
  • Update various scripts (list TBD)
  • Run and commit the results of the migration script
  • Write release notes entry
  • Publish a SemVer major release

How impactful do you think this enhancement will be?

I don't understand the question and I won't respond to it.

Do you have anything more you want to share?

No response

@foolip
Copy link
Collaborator

foolip commented Mar 26, 2024

Note that depending on the order of the keys in JavaScript actually doesn't work because keys that valid array indices are special in JavaScript and are enumerated first. Regardless of insertion order, the keys "1" and "2" are enumerated before "1.1".

I think the proposal is the right one, and that we should additionally guarantee via CI checks that dates are strictly increasing and that the order matches that which compare-versions produces. It's possible those assumptions will not hold forever, but we should definitely notice when we depart from it and perhaps treat it as a breaking change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 🥇 Nice to have features.
Projects
None yet
Development

No branches or pull requests

4 participants
@ddbeck @foolip @queengooborg and others