Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Breaking: Replace
caniuse
util with a compat
util based on MDN data
Close #2296 Fix #2097 Ref #2114 Ref https://youtu.be/Y94fMxmbMFI
- Loading branch information
Showing
19 changed files
with
694 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
browser-compat-data.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { Identifier, SimpleSupportStatement, SupportStatement } from 'mdn-browser-compat-data/types'; | ||
import * as semver from 'semver'; | ||
|
||
export type UnsupportedBrowsers = string[] | null; | ||
|
||
const enum Support { | ||
No, | ||
Yes, | ||
Unknown | ||
} | ||
|
||
// Map `browserslist` browser names to MDN ones. | ||
const browserToMDN = new Map([ | ||
['and_chr', 'chrome_android'], | ||
['and_ff', 'firefox_android'], | ||
['and_qq', 'qq_android'], | ||
['and_uc', 'uc_android'], | ||
['android', 'webview_android'], | ||
['chrome', 'chrome'], | ||
['edge', 'edge'], | ||
['edge_mob', 'edge_mobile'], | ||
['firefox', 'firefox'], | ||
['ie', 'ie'], | ||
['ios_saf', 'safari_ios'], | ||
['node', 'nodejs'], | ||
['opera', 'opera'], | ||
['safari', 'safari'], | ||
['samsung', 'samsunginternet_android'] | ||
]); | ||
|
||
const coerce = (version: string): string | semver.SemVer => { | ||
return semver.coerce(version) || version; | ||
}; | ||
|
||
/** | ||
* Intepret if the provided statement indicates support for the given browser version. | ||
*/ | ||
const isSupported = (support: SimpleSupportStatement, prefix: string, rawVersion: string): Support => { | ||
const version = coerce(rawVersion); | ||
|
||
// Ignore support that requires users to enable a flag. | ||
if (support.flags) { | ||
return Support.Unknown; | ||
} | ||
|
||
// Ignore support that doesn't match the same prefix. | ||
if (prefix !== (support.prefix || '')) { | ||
return Support.Unknown; | ||
} | ||
|
||
/* | ||
* If feature was added but we don't know when, assume support. | ||
* | ||
* Note: This is likely to change to describe the version of the browser | ||
* which was tested for support (e.g. `version_added = "<=60"`). | ||
* | ||
* https://github.com/mdn/browser-compat-data/issues/3021 | ||
*/ | ||
if (support.version_added === true) { | ||
return Support.Yes; | ||
} | ||
|
||
// If feature was never added, then it's not supported. | ||
if (support.version_added === false) { | ||
return Support.No; | ||
} | ||
|
||
// If a feature was removed before the target version, it's not supported. | ||
if (typeof support.version_removed === 'string' && semver.lte(coerce(support.version_removed), version)) { | ||
return Support.No; | ||
} | ||
|
||
// If feature was added by the target version, it's supported; if after it's not. | ||
if (typeof support.version_added === 'string') { | ||
return semver.lte(coerce(support.version_added), version) ? Support.Yes : Support.No; | ||
} | ||
|
||
// Ignore all other cases (e.g. if a feature was removed but we don't know when). | ||
return Support.Unknown; | ||
}; | ||
|
||
/** | ||
* Interpret if the provided support statements indicate the given browser version in supported. | ||
*/ | ||
const isBrowserUnsupported = (support: SupportStatement, prefix: string, version: string): boolean => { | ||
// Convert single entries to an array for consistent handling. | ||
const browserSupport = Array.isArray(support) ? support : [support]; | ||
let status = Support.Unknown; | ||
|
||
// Items are listed from newest to oldest. The first clear rule wins. | ||
for (const simpleSupport of browserSupport) { | ||
switch (isSupported(simpleSupport, prefix, version)) { | ||
case Support.Yes: | ||
return false; | ||
case Support.No: | ||
status = Support.No; | ||
break; // Keep looking in case a feature was temporarily removed. | ||
case Support.Unknown: | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
return status === Support.No; | ||
}; | ||
|
||
/** | ||
* Return provided browsers which don't support the specified feature. | ||
* Browsers are an array of strings as generated by `browserslist`: | ||
* https://github.com/browserslist/browserslist | ||
* | ||
* @param feature An MDN feature `Identifier` with `__compat` data. | ||
* @param browsers A list of target browsers (e.g. `['chrome 74', 'ie 11']`). | ||
*/ | ||
export const getUnsupportedBrowsers = (feature: Identifier | undefined, prefix: string, browsers: string[]): UnsupportedBrowsers => { | ||
if (!feature || !feature.__compat) { | ||
return null; // Assume support if no matching feature was provided. | ||
} | ||
|
||
const support = feature.__compat.support; | ||
const unsupported: string[] = []; | ||
|
||
for (const browser of browsers) { | ||
const [name, version] = browser.split(' '); | ||
const mdnBrowser = browserToMDN.get(name)!; | ||
const browserSupport = support[mdnBrowser]; | ||
|
||
if (browserSupport && isBrowserUnsupported(browserSupport, prefix, version)) { | ||
unsupported.push(browser); | ||
} | ||
} | ||
|
||
return unsupported.length ? unsupported : null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
type Value = string[] | null; | ||
|
||
const cache = new Map<string, Map<string[], Value>>(); | ||
|
||
const _hasCachedValue = (key: string, browsers: string[]): boolean => { | ||
return cache.has(key) && cache.get(key)!.has(browsers); | ||
}; | ||
|
||
const _getCachedValue = (key: string, browsers: string[]): Value => { | ||
return cache.has(key) && cache.get(key)!.get(browsers) || null; | ||
}; | ||
|
||
const _setCachedValue = (key: string, browsers: string[], value: Value): Value => { | ||
if (!cache.has(key)) { | ||
cache.set(key, new Map()); | ||
} | ||
|
||
cache.get(key)!.set(browsers, value); | ||
|
||
return value; | ||
}; | ||
|
||
/** | ||
* Cache a set of unsupported browsers for the provided key and target | ||
* browsers. Speeds up access for repeat queries which are common when | ||
* processing source code. | ||
*/ | ||
export const getCachedValue = (key: string, browsers: string[], getValue: () => Value) => { | ||
if (_hasCachedValue(key, browsers)) { | ||
return _getCachedValue(key, browsers); | ||
} | ||
|
||
return _setCachedValue(key, browsers, getValue()); | ||
}; |
Oops, something went wrong.