ludus/out/goog/labs/useragent/browser.js
2023-11-16 13:22:15 -05:00

793 lines
28 KiB
JavaScript

/*TRANSPILED*/goog.loadModule(function(exports) {'use strict';/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Closure user agent detection (Browser).
* @see <a href="http://www.useragentstring.com/">User agent strings</a>
* For more information on rendering engine, platform, or device see the other
* sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform,
* goog.labs.userAgent.device respectively.)
*/
goog.module('goog.labs.userAgent.browser');
goog.module.declareLegacyNamespace();
const util = goog.require('goog.labs.userAgent.util');
const {AsyncValue, Version} = goog.require('goog.labs.userAgent.highEntropy.highEntropyValue');
const {assert, assertExists} = goog.require('goog.asserts');
const {compareVersions} = goog.require('goog.string.internal');
const {fullVersionList} = goog.require('goog.labs.userAgent.highEntropy.highEntropyData');
const {useClientHints} = goog.require('goog.labs.userAgent');
// TODO(nnaze): Refactor to remove excessive exclusion logic in matching
// functions.
/**
* A browser brand represents an opaque string that is used for making
* brand-specific version checks in userAgentData.
* @enum {string}
*/
const Brand = {
/**
* The browser brand for Android Browser.
* Do not depend on the value of this string. Because Android Browser has not
* implemented userAgentData yet, the value of this string is not guaranteed
* to stay the same in future revisions.
*/
ANDROID_BROWSER: 'Android Browser',
/**
* The browser brand for Chromium, including Chromium-based Edge and Opera.
*/
CHROMIUM: 'Chromium',
/**
* The browser brand for Edge.
* This brand can be used to get the version of both EdgeHTML and
* Chromium-based Edge.
*/
EDGE: 'Microsoft Edge',
/**
* The browser brand for Firefox.
* Do not depend on the value of this string. Because Firefox has not
* implemented userAgentData yet, the value of this string is not guaranteed
* to stay the same in future revisions.
*/
FIREFOX: 'Firefox',
/**
* The browser brand for Internet Explorer.
* Do not depend on the value of this string. Because IE will never support
* userAgentData, the value of this string should be treated as opaque (it's
* used internally for legacy-userAgent fallback).
*/
IE: 'Internet Explorer',
/**
* The browser brand for Opera.
* This brand can be used to get the version of both Presto- and
* Chromium-based Opera.
*/
OPERA: 'Opera',
/**
* The browser brand for Safari.
* Do not depend on the value of this string. Because Safari has not
* implemented userAgentData yet, the value of this string is not guaranteed
* to stay the same in future revisions.
*/
SAFARI: 'Safari',
/**
* The browser brand for Silk.
* See
* https://docs.aws.amazon.com/silk/latest/developerguide/what-is-silk.html
* Do not depend on the value of this string. Because Silk does not
* identify itself in userAgentData yet, the value of this string is not
* guaranteed to stay the same in future revisions.
*/
SILK: 'Silk',
};
exports.Brand = Brand;
/**
* @param {boolean=} ignoreClientHintsFlag Iff truthy, the `useClientHints`
* function will not be called when evaluating if User-Agent Client Hints
* Brand data can be used. For existing labs.userAgent API surfaces with
* widespread use, this should be a falsy value so that usage of the Client
* Hints APIs can be gated behind flags / experiment rollouts.
* @return {boolean} Whether to use navigator.userAgentData to determine
* browser's brand.
*/
function useUserAgentDataBrand(ignoreClientHintsFlag = false) {
if (util.ASSUME_CLIENT_HINTS_SUPPORT) return true;
// High-entropy API surfaces should not be gated behind the useClientHints
// check (as in production it is gated behind a define).
if (!ignoreClientHintsFlag && !useClientHints()) return false;
const userAgentData = util.getUserAgentData();
return !!userAgentData && userAgentData.brands.length > 0;
}
/**
* @return {boolean} Whether this browser is likely to have the fullVersionList
* high-entropy Client Hint.
*/
function hasFullVersionList() {
// https://chromiumdash.appspot.com/commits?commit=1eb643c3057e64ff4d22468432ad16c4cab12879&platform=Linux
// indicates that for all platforms Chromium 98 shipped this feature.
// See also
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA-Full-Version-List#browser_compatibility
return isAtLeast(Brand.CHROMIUM, 98);
}
/**
* @return {boolean} Whether the user's browser is Opera. Note: Chromium based
* Opera (Opera 15+) is detected as Chrome to avoid unnecessary special
* casing.
*/
function matchOpera() {
if (useUserAgentDataBrand()) {
// Pre-Chromium Edge doesn't support navigator.userAgentData.
return false;
}
return util.matchUserAgent('Opera');
}
/** @return {boolean} Whether the user's browser is IE. */
function matchIE() {
if (useUserAgentDataBrand()) {
// IE doesn't support navigator.userAgentData.
return false;
}
return util.matchUserAgent('Trident') || util.matchUserAgent('MSIE');
}
/**
* @return {boolean} Whether the user's browser is Edge. This refers to
* EdgeHTML based Edge.
*/
function matchEdgeHtml() {
if (useUserAgentDataBrand()) {
// Pre-Chromium Edge doesn't support navigator.userAgentData.
return false;
}
return util.matchUserAgent('Edge');
}
/** @return {boolean} Whether the user's browser is Chromium based Edge. */
function matchEdgeChromium() {
if (useUserAgentDataBrand()) {
return util.matchUserAgentDataBrand(Brand.EDGE);
}
return util.matchUserAgent('Edg/');
}
/** @return {boolean} Whether the user's browser is Chromium based Opera. */
function matchOperaChromium() {
if (useUserAgentDataBrand()) {
return util.matchUserAgentDataBrand(Brand.OPERA);
}
return util.matchUserAgent('OPR');
}
/** @return {boolean} Whether the user's browser is Firefox. */
function matchFirefox() {
// Firefox doesn't support navigator.userAgentData yet, so use
// navigator.userAgent.
return util.matchUserAgent('Firefox') || util.matchUserAgent('FxiOS');
}
/** @return {boolean} Whether the user's browser is Safari. */
function matchSafari() {
// Apple-based browsers don't support navigator.userAgentData yet, so use
// navigator.userAgent.
return util.matchUserAgent('Safari') &&
!(matchChrome() || matchCoast() || matchOpera() || matchEdgeHtml() ||
matchEdgeChromium() || matchOperaChromium() || matchFirefox() ||
isSilk() || util.matchUserAgent('Android'));
}
/**
* @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based
* iOS browser).
*/
function matchCoast() {
if (useUserAgentDataBrand()) {
// Coast doesn't support navigator.userAgentData.
return false;
}
return util.matchUserAgent('Coast');
}
/** @return {boolean} Whether the user's browser is iOS Webview. */
function matchIosWebview() {
// Apple-based browsers don't support navigator.userAgentData yet, so use
// navigator.userAgent.
// iOS Webview does not show up as Chrome or Safari.
return (util.matchUserAgent('iPad') || util.matchUserAgent('iPhone')) &&
!matchSafari() && !matchChrome() && !matchCoast() && !matchFirefox() &&
util.matchUserAgent('AppleWebKit');
}
/**
* @return {boolean} Whether the user's browser is any Chromium browser. This
* returns true for Chrome, Opera 15+, and Edge Chromium.
*/
function matchChrome() {
if (useUserAgentDataBrand()) {
return util.matchUserAgentDataBrand(Brand.CHROMIUM);
}
return ((util.matchUserAgent('Chrome') || util.matchUserAgent('CriOS')) &&
!matchEdgeHtml()) ||
isSilk();
}
/** @return {boolean} Whether the user's browser is the Android browser. */
function matchAndroidBrowser() {
// Android can appear in the user agent string for Chrome on Android.
// This is not the Android standalone browser if it does.
return util.matchUserAgent('Android') &&
!(isChrome() || isFirefox() || isOpera() || isSilk());
}
/** @return {boolean} Whether the user's browser is Opera. */
const isOpera = matchOpera;
exports.isOpera = isOpera;
/** @return {boolean} Whether the user's browser is IE. */
const isIE = matchIE;
exports.isIE = isIE;
/** @return {boolean} Whether the user's browser is EdgeHTML based Edge. */
const isEdge = matchEdgeHtml;
exports.isEdge = isEdge;
/** @return {boolean} Whether the user's browser is Chromium based Edge. */
const isEdgeChromium = matchEdgeChromium;
exports.isEdgeChromium = isEdgeChromium;
/** @return {boolean} Whether the user's browser is Chromium based Opera. */
const isOperaChromium = matchOperaChromium;
exports.isOperaChromium = isOperaChromium;
/** @return {boolean} Whether the user's browser is Firefox. */
const isFirefox = matchFirefox;
exports.isFirefox = isFirefox;
/** @return {boolean} Whether the user's browser is Safari. */
const isSafari = matchSafari;
exports.isSafari = isSafari;
/**
* @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based
* iOS browser).
*/
const isCoast = matchCoast;
exports.isCoast = isCoast;
/** @return {boolean} Whether the user's browser is iOS Webview. */
const isIosWebview = matchIosWebview;
exports.isIosWebview = isIosWebview;
/**
* @return {boolean} Whether the user's browser is any Chromium based browser (
* Chrome, Blink-based Opera (15+) and Edge Chromium).
*/
const isChrome = matchChrome;
exports.isChrome = isChrome;
/** @return {boolean} Whether the user's browser is the Android browser. */
const isAndroidBrowser = matchAndroidBrowser;
exports.isAndroidBrowser = isAndroidBrowser;
/**
* For more information, see:
* http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
* @return {boolean} Whether the user's browser is Silk.
*/
function isSilk() {
// As of Silk 93, Silk does not identify itself in userAgentData.brands.
// When Silk changes this behavior, update this method to call
// matchUserAgentDataBrand (akin to isChrome, etc.)
return util.matchUserAgent('Silk');
}
exports.isSilk = isSilk;
/**
* A helper function that returns a function mapping a list of candidate
* version tuple keys to the first version string present under a key.
* Ex:
* <code>
* // Arg extracted from "Foo/1.2.3 Bar/0.2021"
* const mapVersion = createVersionMap([["Foo", "1.2.3"], ["Bar", "0.2021"]]);
* mapVersion(["Bar", "Foo"]); // returns "0.2021"
* mapVersion(["Baz", "Foo"]); // returns "1.2.3"
* mapVersion(["Baz", "???"]); // returns ""
* </code>
* @param {!Array<!Array<string>>} versionTuples Version tuples pre-extracted
* from a user agent string.
* @return {function(!Array<string>): string} The version string, or empty
* string if it doesn't exist under the given key.
*/
function createVersionMap(versionTuples) {
// Construct a map for easy lookup.
const versionMap = {};
versionTuples.forEach((tuple) => {
// Note that the tuple is of length three, but we only care about the
// first two.
const key = tuple[0];
const value = tuple[1];
versionMap[key] = value;
});
// Gives the value with the first key it finds, otherwise empty string.
return (keys) => versionMap[keys.find((key) => key in versionMap)] || '';
}
/**
* Returns the browser version.
*
* Note that for browsers with multiple brands, this function assumes a primary
* brand and returns the version for that brand.
*
* Additionally, this function is not userAgentData-aware and will return
* incorrect values when the User Agent string is frozen. The current status of
* User Agent string freezing is available here:
* https://www.chromestatus.com/feature/5704553745874944
*
* To mitigate both of these potential issues, use
* getVersionStringForLogging() or fullVersionOf() instead.
*
* @return {string} The browser version or empty string if version cannot be
* determined. Note that for Internet Explorer, this returns the version of
* the browser, not the version of the rendering engine. (IE 8 in
* compatibility mode will return 8.0 rather than 7.0. To determine the
* rendering engine version, look at document.documentMode instead. See
* http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more
* details.)
*/
function getVersion() {
const userAgentString = util.getUserAgent();
// Special case IE since IE's version is inside the parenthesis and
// without the '/'.
if (isIE()) {
return getIEVersion(userAgentString);
}
const versionTuples = util.extractVersionTuples(userAgentString);
const lookUpValueWithKeys = createVersionMap(versionTuples);
// Check Opera before Chrome since Opera 15+ has "Chrome" in the string.
// See
// http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond
if (isOpera()) {
// Opera 10 has Version/10.0 but Opera/9.8, so look for "Version" first.
// Opera uses 'OPR' for more recent UAs.
return lookUpValueWithKeys(['Version', 'Opera']);
}
// Check Edge before Chrome since it has Chrome in the string.
if (isEdge()) {
return lookUpValueWithKeys(['Edge']);
}
// Check Chromium Edge before Chrome since it has Chrome in the string.
if (isEdgeChromium()) {
return lookUpValueWithKeys(['Edg']);
}
// Check Silk before Chrome since it may have Chrome in its string and be
// treated as Chrome.
if (isSilk()) {
return lookUpValueWithKeys(['Silk']);
}
if (isChrome()) {
return lookUpValueWithKeys(['Chrome', 'CriOS', 'HeadlessChrome']);
}
// Usually products browser versions are in the third tuple after "Mozilla"
// and the engine.
const tuple = versionTuples[2];
return tuple && tuple[1] || '';
}
exports.getVersion = getVersion;
/**
* Returns whether the current browser's version is at least as high as the
* given one.
*
* Note that for browsers with multiple brands, this function assumes a primary
* brand and checks the version for that brand.
*
* Additionally, this function is not userAgentData-aware and will return
* incorrect values when the User Agent string is frozen. The current status of
* User Agent string freezing is available here:
* https://www.chromestatus.com/feature/5704553745874944
*
* To mitigate both of these potential issues, use isAtLeast()/isAtMost() or
* fullVersionOf() instead.
*
* @param {string|number} version The version to check.
* @return {boolean} Whether the browser version is higher or the same as the
* given version.
* @deprecated Use isAtLeast()/isAtMost() instead.
*/
function isVersionOrHigher(version) {
return compareVersions(getVersion(), version) >= 0;
}
exports.isVersionOrHigher = isVersionOrHigher;
/**
* A helper function to determine IE version. More information:
* http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString
* http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
* http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx
* http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx
* @param {string} userAgent the User-Agent.
* @return {string}
*/
function getIEVersion(userAgent) {
// IE11 may identify itself as MSIE 9.0 or MSIE 10.0 due to an IE 11 upgrade
// bug. Example UA:
// Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; rv:11.0)
// like Gecko.
// See http://www.whatismybrowser.com/developers/unknown-user-agent-fragments.
const rv = /rv: *([\d\.]*)/.exec(userAgent);
if (rv && rv[1]) {
return rv[1];
}
let version = '';
const msie = /MSIE +([\d\.]+)/.exec(userAgent);
if (msie && msie[1]) {
// IE in compatibility mode usually identifies itself as MSIE 7.0; in this
// case, use the Trident version to determine the version of IE. For more
// details, see the links above.
const tridentVersion = /Trident\/(\d.\d)/.exec(userAgent);
if (msie[1] == '7.0') {
if (tridentVersion && tridentVersion[1]) {
switch (tridentVersion[1]) {
case '4.0':
version = '8.0';
break;
case '5.0':
version = '9.0';
break;
case '6.0':
version = '10.0';
break;
case '7.0':
version = '11.0';
break;
}
} else {
version = '7.0';
}
} else {
version = msie[1];
}
}
return version;
}
/**
* A helper function to return the navigator.userAgent-supplied full version
* number of the current browser or an empty string, based on whether the
* current browser is the one specified.
* @param {string} browser The brand whose version should be returned.
* @return {string}
*/
function getFullVersionFromUserAgentString(browser) {
const userAgentString = util.getUserAgent();
// Special case IE since IE's version is inside the parenthesis and
// without the '/'.
if (browser === Brand.IE) {
return isIE() ? getIEVersion(userAgentString) : '';
}
const versionTuples = util.extractVersionTuples(userAgentString);
const lookUpValueWithKeys = createVersionMap(versionTuples);
switch (browser) {
case Brand.OPERA:
// Opera 10 has Version/10.0 but Opera/9.8, so look for "Version"
// first. Opera uses 'OPR' for more recent UAs.
if (isOpera()) {
return lookUpValueWithKeys(['Version', 'Opera']);
} else if (isOperaChromium()) {
return lookUpValueWithKeys(['OPR']);
}
break;
case Brand.EDGE:
if (isEdge()) {
return lookUpValueWithKeys(['Edge']);
} else if (isEdgeChromium()) {
return lookUpValueWithKeys(['Edg']);
}
break;
case Brand.CHROMIUM:
if (isChrome()) {
return lookUpValueWithKeys(['Chrome', 'CriOS', 'HeadlessChrome']);
}
break;
}
// For the following browsers, the browser version is in the third tuple after
// "Mozilla" and the engine.
if ((browser === Brand.FIREFOX && isFirefox()) ||
(browser === Brand.SAFARI && isSafari()) ||
(browser === Brand.ANDROID_BROWSER && isAndroidBrowser()) ||
(browser === Brand.SILK && isSilk())) {
const tuple = versionTuples[2];
return tuple && tuple[1] || '';
}
return '';
}
/**
* Returns the major version of the given browser brand, or NaN if the current
* browser is not the given brand.
* Note that the major version number may be different depending on which
* browser is specified. The returned value can be used to make browser version
* comparisons using comparison operators.
* @private
* @param {!Brand} browser The brand whose version should be returned.
* @return {number} The major version number associated with the current
* browser under the given brand, or NaN if the current browser doesn't match
* the given brand.
*/
function versionOf_(browser) {
let versionParts;
// Silk currently does not identify itself in its userAgentData.brands array,
// so if checking its version, always fall back to the user agent string.
if (useUserAgentDataBrand() && browser !== Brand.SILK) {
const data = util.getUserAgentData();
const matchingBrand = data.brands.find(({brand}) => brand === browser);
if (!matchingBrand || !matchingBrand.version) {
return NaN;
}
versionParts = matchingBrand.version.split('.');
} else {
const fullVersion = getFullVersionFromUserAgentString(browser);
if (fullVersion === '') {
return NaN;
}
versionParts = fullVersion.split('.');
}
if (versionParts.length === 0) {
return NaN;
}
const majorVersion = versionParts[0];
return Number(majorVersion); // Returns NaN if it is not parseable.
}
/**
* Returns true if the current browser matches the given brand and is at least
* the given major version. The major version must be a whole number (i.e.
* decimals should not be used to represent a minor version).
* @param {!Brand} brand The brand whose version should be returned.
* @param {number} majorVersion The major version number to compare against.
* This must be a whole number.
* @return {boolean} Whether the current browser both matches the given brand
* and is at least the given version.
*/
function isAtLeast(brand, majorVersion) {
assert(
Math.floor(majorVersion) === majorVersion,
'Major version must be an integer');
return versionOf_(brand) >= majorVersion;
}
exports.isAtLeast = isAtLeast;
/**
* Returns true if the current browser matches the given brand and is at most
* the given version. The major version must be a whole number (i.e. decimals
* should not be used to represent a minor version).
* @param {!Brand} brand The brand whose version should be returned.
* @param {number} majorVersion The major version number to compare against.
* This must be a whole number.
* @return {boolean} Whether the current browser both matches the given brand
* and is at most the given version.
*/
function isAtMost(brand, majorVersion) {
assert(
Math.floor(majorVersion) === majorVersion,
'Major version must be an integer');
return versionOf_(brand) <= majorVersion;
}
exports.isAtMost = isAtMost;
/**
* Loads the high-entropy browser brand/version data and wraps the correct
* version string in a Version object.
* @implements {AsyncValue<!Version>}
*/
class HighEntropyBrandVersion {
/**
* @param {string} brand The brand whose version is retrieved in this
* container.
* @param {boolean} useUach Whether to attempt to use the User-Agent Client
* Hints (UACH) API surface.
* @param {string} fallbackVersion The fallback version derived from the
* userAgent string.
*/
constructor(brand, useUach, fallbackVersion) {
/** @private @const {string} */
this.brand_ = brand;
/** @private @const {!Version} */
this.version_ = new Version(fallbackVersion);
/** @private @const {boolean} */
this.useUach_ = useUach;
}
/**
* @return {!Version|undefined}
* @override
*/
getIfLoaded() {
if (this.useUach_) {
const loadedVersionList = fullVersionList.getIfLoaded();
if (loadedVersionList !== undefined) {
const matchingBrand =
loadedVersionList.find(({brand}) => this.brand_ === brand);
// We assumed in fullVersionOf that if the fullVersionList is defined
// the brands must match. Double-check this here.
assertExists(matchingBrand);
return new Version(matchingBrand.version);
}
// Fallthrough to fallback on Pre-UACH implementation
}
// We want to make sure the loading semantics of the Pre-UACH implementation
// match those of the UACH implementation. Loading must happen before any
// data can be retrieved from getIfLoaded.
// For HighEntropyBrandVersion, loading can either be done by calling #load
// or by calling the module-local loadFullVersions function.
if (preUachHasLoaded) {
return this.version_;
}
return;
}
/**
* @return {!Promise<!Version>}
* @override
*/
async load() {
if (this.useUach_) {
const loadedVersionList = await fullVersionList.load();
if (loadedVersionList !== undefined) {
const matchingBrand =
loadedVersionList.find(({brand}) => this.brand_ === brand);
assertExists(matchingBrand);
return new Version(matchingBrand.version);
}
// Fallthrough to fallback on Pre-UACH implementation
} else {
// Await something so that calling load with or without UACH API
// availability results in waiting at least one macrotask before allowing
// access to the cached version information.
await 0;
}
// Regardless of whether we are using UACH APIs, we can now allow access to
// the fallback case
preUachHasLoaded = true;
return this.version_;
}
}
/**
* Whether full version data should be considered available when using UACH
* fallback implementations. This is flipped to true when either
* loadFullVersions or HighEntropyBrandVersion.prototype.load are called,
* matching the global singleton semantics of the UACH codepaths.
*/
let preUachHasLoaded = false;
/**
* Requests all full browser versions to be cached. When the returned promise
* resolves, subsequent calls to `fullVersionOf(...).getIfLoaded()` will return
* a value.
*
* This method should be avoided in favor of directly awaiting
* `fullVersionOf(...).load()` where it is used.
*
* @return {!Promise<void>}
*/
async function loadFullVersions() {
if (useUserAgentDataBrand(true)) {
await fullVersionList.load();
}
preUachHasLoaded = true;
}
exports.loadFullVersions = loadFullVersions;
/**
* Resets module-local caches used by functionality in this module.
* This is only for use by goog.labs.userAgent.testUtil.resetUserAgent (and
* labs.userAgent tests).
* @package
*/
exports.resetForTesting = () => {
preUachHasLoaded = false;
fullVersionList.resetForTesting();
};
/**
* Returns an object that provides access to the full version string of the
* current browser -- or undefined, based on whether the current browser matches
* the requested browser brand. Note that the full version string is a
* high-entropy value, and must be asynchronously loaded before it can be
* accessed synchronously.
* @param {!Brand} browser The brand whose version should be returned.
* @return {!AsyncValue<!Version>|undefined} An object that can be used
* to get or load the full version string as a high-entropy value, or
* undefined if the current browser doesn't match the given brand.
*/
function fullVersionOf(browser) {
let fallbackVersionString = '';
// If we are reasonably certain now that the browser we are on has the
// fullVersionList high-entropy hint, then we can skip computing the fallback
// value as we won't end up using it.
if (!hasFullVersionList()) {
fallbackVersionString = getFullVersionFromUserAgentString(browser);
}
// Silk has the UACH API surface, but currently does not identify itself in
// the userAgentData.brands array. Fallback to using userAgent string version
// for Silk.
const useUach = browser !== Brand.SILK && useUserAgentDataBrand(true);
if (useUach) {
const data = util.getUserAgentData();
// Operate under the assumption that the low-entropy and high-entropy lists
// of brand/version pairs contain an identical set of brands. Therefore, if
// the low-entropy list doesn't contain the given brand, return undefined.
if (!data.brands.find(({brand}) => brand === browser)) {
return undefined;
}
} else if (fallbackVersionString === '') {
return undefined;
}
return new HighEntropyBrandVersion(browser, useUach, fallbackVersionString);
}
exports.fullVersionOf = fullVersionOf;
/**
* Returns a version string for the current browser or undefined, based on
* whether the current browser is the one specified.
* This value should ONLY be used for logging/debugging purposes. Do not use it
* to branch code paths. For comparing versions, use isAtLeast()/isAtMost() or
* fullVersionOf() instead.
* @param {!Brand} browser The brand whose version should be returned.
* @return {string} The version as a string.
*/
function getVersionStringForLogging(browser) {
if (useUserAgentDataBrand(true)) {
const fullVersionObj = fullVersionOf(browser);
if (fullVersionObj) {
const fullVersion = fullVersionObj.getIfLoaded();
if (fullVersion) {
return fullVersion.toVersionStringForLogging();
}
// No full version, return the major version instead.
const data = util.getUserAgentData();
const matchingBrand = data.brands.find(({brand}) => brand === browser);
// Checking for the existence of matchingBrand is not necessary because
// the existence of fullVersionObj implies that there is already a
// matching brand.
assertExists(matchingBrand);
return matchingBrand.version;
}
// If fullVersionObj is undefined, this doesn't mean that the full version
// is unavailable, but rather that the current browser doesn't match the
// input `browser` argument.
return '';
} else {
return getFullVersionFromUserAgentString(browser);
}
}
exports.getVersionStringForLogging = getVersionStringForLogging;
;return exports;});