-
Notifications
You must be signed in to change notification settings - Fork 199
compute-baseline: add method to expand a support statement into per-release support information
#1312
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
Conversation
…-release support information
| */ | ||
| toReleaseSupportMap(): ReleaseSupportMap { | ||
| if (this.browser === undefined) { | ||
| throw Error("This support statement's browser is unknown."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| throw Error("This support statement's browser is unknown."); | |
| throw new Error("This support statement's browser is unknown."); |
| // returning `[this.browser.current()]` at least. | ||
| supportedBy(): { release: Release; qualifications?: Qualifications }[] { | ||
| if (this.browser === undefined) { | ||
| throw Error("This support statement's browser is unknown."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| throw Error("This support statement's browser is unknown."); | |
| throw new Error("This support statement's browser is unknown."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a problem in a bunch of places. I'll open a follow-up PR to fix this across the board.
| throw Error("This support statement's browser is unknown."); | ||
| } | ||
|
|
||
| if (this.version_added === false || this.version_removed === true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If version_removed is true, support is unknown for everything except the version_added version.
| let startRanged = false; | ||
| if (this.version_added === true) { | ||
| startRanged = true; | ||
| start = this.browser.current(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct, but if this code is actually used, our dist files will keep changing. Should we instead refuse to work with true values and wait for them to be fixed in BCD?
| * Expand this support statement into a `Map` from `Release` objects to objects | ||
| * describing whether the release is supporting, unsupporting, or unknown. | ||
| */ | ||
| toReleaseSupportMap(): ReleaseSupportMap { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this expands a single support statement (not an array) into a map. That means the resulting map will always be simple, typically with an initial run of false values followed by a run or true values. Sometimes unknown support before a point, but never flip-flopping. Is a map really necessary to represent this, or should we just parse version_added and version_removed into a form that makes it easy to get support for a specific release?
|
|
||
| let end: Release | undefined; | ||
| if (this.version_removed) { | ||
| end = this.browser.version(this.version_removed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about ranges here?
| if (isQualified && r.inRange(start, end)) { | ||
| // Supported with qualifications | ||
| result.set(r, { supported: true, qualifications }); | ||
| } else if (r.inRange(start, end)) { | ||
| // Supported without qualification | ||
| result.set(r, { supported: true }); | ||
| } else if (startRanged && !r.inRange(start)) { | ||
| // Support unknown (before a ≤ version) | ||
| result.set(r, { supported: null }); | ||
| } else { | ||
| // Unsupported (outside a hard range) | ||
| result.set(r, { supported: false }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about putting this into a method to get support for a specific release? That's cheaper when the caller doesn't want to know about all releases.
| * Find out whether this support statement says a given browser release is | ||
| * supported (with or without qualifications), unsupported, or unknown. | ||
| */ | ||
| supportedIn(release: Release): Supported | Unsupported | UnknownSupport { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@foolip I've refactored this as a method that just checks whether one release is supported. If one still wants to know the situation for every release, then that's a one-liner away:
new Map(browser.releases.map(r => [r, statement.supportedIn(r)]))
Also, doing this for any arbitrary support statement, while possible, was getting very tricky and hard to follow. Since we don't need this I decided it wasn't worth the effort, so it's only available on RealSupportStatements.
(I've kept some test cases and work from the all-values version, but it's not urgent, so I'll re-introduce that when there's an actual need or a spare couple of hours for it.)
| assert.throws(() => cr.version("50").inRange(fx.version("50")), Error); | ||
| }); | ||
|
|
||
| it("handles closed ranges", function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test for when the version equals the end version, to show the range is exclusive of the end point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with 7c2bbad.
| assert.equal(ranged.supportedIn(cr.version("99")).supported, null); | ||
| assert.equal(ranged.supportedIn(cr.version("100")).supported, true); | ||
| assert.equal(ranged.supportedIn(cr.version("101")).supported, true); | ||
| assert.equal(ranged.supportedIn(cr.version("124")).supported, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not the 125 assert here, so it's the same asserts for unranged and ranged? (You might remove 101 if you want to reduce the number of rows.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with 4e0110b.
| ); | ||
|
|
||
| assert.equal(rangedEnd.supportedIn(cr.version("100")).supported, true); | ||
| assert.equal(rangedEnd.supportedIn(cr.version("124")).supported, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also test 101 here to make it clear that there's just a single release we're sure about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with 4e0110b.
packages/compute-baseline/src/browser-compat-data/supportStatements.test.ts
Outdated
Show resolved
Hide resolved
| return qualifications; | ||
| } | ||
|
|
||
| function isRangedVersion(s: any): s is string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've only seen this syntax once before, but does s is string really do the right thing if this method returns false? Won't TypeScript infer that the argument wasn't a string even though it may have been?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this really does the right thing. Type predicates are (by themselves) one-way: if the function returns true, then the type is satisfied. The inverse (false → s is not string) is not inferred. Demo.
AFAICT, even in general TypeScript doesn't actually track the list of types something isn't, just the set of remaining possible types.
Co-authored-by: Philip Jägenstedt <philip@foolip.org>
This is another incremental step toward handling version ranges more completely, by taking a support statement and mapping it to every release that a browser has.
More specifically, this PR:
Adds
toReleaseSupportMap()method toSupportStatements. It's very much likesupportedBy(), except it has something to say about every version, not just the supporting versions. I've made some ofsupportedBy()reusable. Eventually, but not today, we'll rip outsupportedBy()entirely.Adds an
inRange(start, end?)method toReleasess. This is a not-infrequent thing to check and remembering what>= 0means is hard.Remove some never-used code relating to ranges.
Handle bugged
version_removedvalues in BCD. Basically, some values should never happen according to the schema, but are happening anyway. This won't be completely fixed until it gets fixed upstream.The next step after this will be to reconcile multiple support statements at the feature level (i.e., filtering out "unsupported" entries when there's a competing "supported" entry) and do it across browsers (e.g., to create something like
Map<Browser, Map<Release, Supported | Unsupported | UnknownSupport>>).