browserslist-generator
Version:
A library that makes generating and validating Browserslists a breeze!
1 lines • 128 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/browserslist-generator/browserslist-generator.ts","../src/browserslist-generator/browser-version.ts","../src/browserslist-generator/ensure-semver.ts","../src/browserslist-generator/compare-versions.ts","../src/browserslist-generator/normalize-browser-version-regexp.ts","../src/browserslist-generator/util.ts","../src/browserslist-generator/constant.ts","../src/browserslist-generator/ecma-version.ts","../src/browserslist-generator/range-correction.ts","../src/browserslist-generator/ua-parser-wrapper.ts"],"sourcesContent":["export * from \"./browserslist-generator/browserslist-generator.js\";\n","import Browserslist from \"browserslist\";\nimport {feature as caniuseFeature, features as caniuseFeatures, type StatsByAgentID} from \"caniuse-lite\";\nimport * as compatData from \"@mdn/browser-compat-data\" with {type: \"json\"};\nimport objectPath from \"object-path\";\nimport {gt, gte, lt, lte} from \"semver\";\nimport {\n\tgetClosestMatchingBrowserVersion,\n\tgetNextVersionOfBrowser,\n\tgetOldestVersionOfBrowser,\n\tgetPreviousVersionOfBrowser,\n\tgetSortedBrowserVersions,\n\tgetSortedBrowserVersionsWithLeadingVersion,\n\tnormalizeBrowserVersion\n} from \"./browser-version.js\";\nimport {UNKNOWN_CANIUSE_BROWSER} from \"./constant.js\";\nimport {ensureSemver, coerceToString} from \"./ensure-semver.js\";\nimport {compareVersions} from \"./compare-versions.js\";\nimport type {ComparisonOperator} from \"./comparison-operator.js\";\nimport type {EcmaVersion} from \"./ecma-version.js\";\nimport {\n\tES2015_FEATURES,\n\tES2016_FEATURES,\n\tES2017_FEATURES,\n\tES2018_FEATURES,\n\tES2019_FEATURES,\n\tES2020_FEATURES,\n\tES2021_FEATURES,\n\tES2022_FEATURES,\n\tES2023_FEATURES,\n\tES2024_FEATURES,\n\tES5_FEATURES\n} from \"./ecma-version.js\";\nimport {rangeCorrection} from \"./range-correction.js\";\nimport type {BrowserSupportForFeaturesCommonResult} from \"./browser-support-for-features-common-result.js\";\nimport type {CaniuseBrowser, CaniuseStatsNormalized, CaniuseBrowserCorrection, VersionedCaniuseBrowser, CaniuseSupportKind} from \"./i-caniuse.js\";\nimport type {Mdn, MdnBrowserName, MdnSupportDict} from \"./mdn.js\";\nimport {NORMALIZE_BROWSER_VERSION_REGEXP} from \"./normalize-browser-version-regexp.js\";\nimport {UaParserWrapper} from \"./ua-parser-wrapper.js\";\nimport type {UseragentBrowser, UseragentEngine, UseragentOs} from \"./useragent/useragent-typed.js\";\nimport type {MaybeArray, Mutable} from \"helpertypes\";\n\n/**\n * A Cache between user agent names and generated Browserslists\n */\nconst userAgentToBrowserslistCache = new Map<string, string[]>();\n\n/**\n * A Cache for retrieving browser support for some features\n */\nconst browserSupportForFeaturesCache = new Map<string, BrowserSupportForFeaturesCommonResult>();\n\n/**\n * A Cache between feature names and their CaniuseStats\n */\nconst featureToCaniuseStatsCache = new Map<string, CaniuseStatsNormalized>();\n\n/**\n * A Cache between user agents with any amount of features and whether or not they are supported by the user agent\n */\nconst userAgentWithFeaturesToSupportCache = new Map<string, boolean>();\n\n/**\n * By and large, MDN has the best compat data, especially when looking into at which point older version of Android-based browsers\n * received support for a feature. Therefore we generally prioritize MDN compat data and will attempt to rewrite common caniuse queries to\n * their respective MDN feature names\n */\nconst CANIUSE_TO_MDN_FEATURE_MAP = {\n\tpointer: \"api.PointerEvent.PointerEvent\",\n\tshadowdomv1: \"api.ShadowRoot\",\n\t\"custom-elementsv1\": \"api.CustomElementRegistry\",\n\ttemplate: \"html.elements.template\",\n\tfetch: \"api.fetch\",\n\tpromises: \"javascript.builtins.Promise\",\n\t\"object-values\": \"javascript.builtins.Object.values\",\n\tmutationobserver: \"api.MutationObserver\",\n\t\"focusin-focusout-events\": \"api.Element.focusin_event\",\n\t\"high-resolution-time\": \"api.Performance.now\",\n\turl: \"api.URL\",\n\turlsearchparams: \"api.URLSearchParams\",\n\t\"object-fit\": \"css.properties.object-fit\",\n\t\"console-basic\": \"api.console.info\",\n\t\"console-time\": \"api.console.time\",\n\t\"atob-btoa\": \"api.atob\",\n\tblobbuilder: \"api.Blob.Blob\",\n\tbloburls: \"api.URL.createObjectURL\",\n\trequestidlecallback: \"api.Window.requestIdleCallback\",\n\trequestanimationframe: \"api.Window.requestAnimationFrame\",\n\tproxy: \"javascript.builtins.Proxy\"\n} as const;\n\n/**\n * A Map between features and browsers that has partial support for them but should be allowed anyway\n * @type {Map<string, string[]>}\n */\nconst PARTIAL_SUPPORT_ALLOWANCES = new Map([\n\t[\"shadowdomv1\", \"*\"],\n\t[\"custom-elementsv1\", \"*\"],\n\t[\"web-animation\", \"*\"]\n]) as Map<string, CaniuseBrowser[] | \"*\">;\n\nconst TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT: CaniuseBrowserCorrection = {\n\t/* eslint-disable @typescript-eslint/naming-convention */\n\tandroid: rangeCorrection(\"android\", \"available\", `4`),\n\tchrome: rangeCorrection(\"and_chr\", \"available\", `7`),\n\tand_chr: rangeCorrection(\"and_chr\", \"available\", `7`),\n\tedge: rangeCorrection(\"edge\", \"available\", \"12\"),\n\tsamsung: rangeCorrection(\"samsung\", \"available\", `4`),\n\topera: rangeCorrection(\"opera\", \"available\", `12`),\n\top_mob: rangeCorrection(\"op_mob\", \"available\", `12`),\n\tfirefox: rangeCorrection(\"firefox\", \"available\", `4`),\n\tand_ff: rangeCorrection(\"and_ff\", \"available\", `4`),\n\tsafari: rangeCorrection(\"safari\", \"available\", `6`),\n\tios_saf: rangeCorrection(\"safari\", \"available\", `5`),\n\tie: rangeCorrection(\"ie\", \"available\", `11`),\n\top_mini: rangeCorrection(\"op_mini\", \"available\", `all`),\n\tbb: rangeCorrection(\"bb\", \"available\", `10`)\n\t/* eslint-enable @typescript-eslint/naming-convention */\n};\n\nconst TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT: CaniuseBrowserCorrection = {\n\t/* eslint-disable @typescript-eslint/naming-convention */\n\tandroid: rangeCorrection(\"android\", \"available\", `45`),\n\tchrome: rangeCorrection(\"and_chr\", \"available\", `45`),\n\tand_chr: rangeCorrection(\"and_chr\", \"available\", `45`),\n\tedge: rangeCorrection(\"edge\", \"available\", \"12\"),\n\tsamsung: rangeCorrection(\"samsung\", \"available\", `5`),\n\topera: rangeCorrection(\"opera\", \"available\", `32`),\n\top_mob: rangeCorrection(\"op_mob\", \"available\", `32`),\n\tfirefox: rangeCorrection(\"firefox\", \"available\", `38`),\n\tand_ff: rangeCorrection(\"and_ff\", \"available\", `38`),\n\tsafari: rangeCorrection(\"safari\", \"available\", `10`),\n\tios_saf: rangeCorrection(\"safari\", \"available\", `10`),\n\tie: rangeCorrection(\"ie\", \"available\", `11`),\n\tie_mob: rangeCorrection(\"ie\", \"available\", `11`)\n\t/* eslint-enable @typescript-eslint/naming-convention */\n};\n\nconst TYPED_ARRAY_ES2016_DATA_CORRECTIONS_INPUT: CaniuseBrowserCorrection = {\n\t/* eslint-disable @typescript-eslint/naming-convention */\n\tandroid: rangeCorrection(\"android\", \"available\", `47`),\n\tchrome: rangeCorrection(\"and_chr\", \"available\", `47`),\n\tand_chr: rangeCorrection(\"and_chr\", \"available\", `47`),\n\tedge: rangeCorrection(\"edge\", \"available\", \"14\"),\n\tsamsung: rangeCorrection(\"samsung\", \"available\", `5`),\n\topera: rangeCorrection(\"opera\", \"available\", `34`),\n\top_mob: rangeCorrection(\"op_mob\", \"available\", `34`),\n\tfirefox: rangeCorrection(\"firefox\", \"available\", `43`),\n\tand_ff: rangeCorrection(\"and_ff\", \"available\", `43`),\n\tsafari: rangeCorrection(\"safari\", \"available\", `10`),\n\tios_saf: rangeCorrection(\"safari\", \"available\", `10`)\n\t/* eslint-enable @typescript-eslint/naming-convention */\n};\n\nconst TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT: CaniuseBrowserCorrection = {\n\t/* eslint-disable @typescript-eslint/naming-convention */\n\tandroid: rangeCorrection(\"android\", \"available\", `38`),\n\tchrome: rangeCorrection(\"and_chr\", \"available\", `38`),\n\tand_chr: rangeCorrection(\"and_chr\", \"available\", `38`),\n\tedge: rangeCorrection(\"edge\", \"available\", \"12\"),\n\tsamsung: rangeCorrection(\"samsung\", \"available\", `5`),\n\topera: rangeCorrection(\"opera\", \"available\", `26`),\n\top_mob: rangeCorrection(\"op_mob\", \"available\", `26`),\n\tfirefox: rangeCorrection(\"firefox\", \"available\", `37`),\n\tand_ff: rangeCorrection(\"and_ff\", \"available\", `37`),\n\tsafari: rangeCorrection(\"safari\", \"available\", `10`),\n\tios_saf: rangeCorrection(\"safari\", \"available\", `10`)\n\t/* eslint-enable @typescript-eslint/naming-convention */\n};\n\nconst TYPED_ARRAY_SPECIES_DATA_CORRECTIONS_INPUT: CaniuseBrowserCorrection = {\n\t/* eslint-disable @typescript-eslint/naming-convention */\n\tandroid: rangeCorrection(\"android\", \"available\", `51`),\n\tchrome: rangeCorrection(\"and_chr\", \"available\", `51`),\n\tand_chr: rangeCorrection(\"and_chr\", \"available\", `51`),\n\tedge: rangeCorrection(\"edge\", \"available\", \"13\"),\n\tsamsung: rangeCorrection(\"samsung\", \"available\", `5`),\n\topera: rangeCorrection(\"opera\", \"available\", `38`),\n\top_mob: rangeCorrection(\"op_mob\", \"available\", `38`),\n\tfirefox: rangeCorrection(\"firefox\", \"available\", `48`),\n\tand_ff: rangeCorrection(\"and_ff\", \"available\", `48`),\n\tsafari: rangeCorrection(\"safari\", \"available\", `10`),\n\tios_saf: rangeCorrection(\"safari\", \"available\", `10`)\n\t/* eslint-enable @typescript-eslint/naming-convention */\n};\n\n/**\n * Not all Caniuse data is entirely correct. For some features, the data on https://kangax.github.io/compat-table/es6/\n * is more correct. When a Browserslist is generated based on support for specific features, it is really important\n * that it is correct, especially if the browserslist will be used as an input to tools such as @babel/preset-env.\n * This table provides some corrections to the Caniuse data that makes it align better with actual availability\n * @type {[string, CaniuseBrowserCorrection][]}\n */\nconst FEATURE_TO_BROWSER_DATA_CORRECTIONS_INPUT: [string, CaniuseBrowserCorrection][] = [\n\t/* eslint-disable @typescript-eslint/naming-convention */\n\t[\n\t\t\"xhr2\",\n\t\t{\n\t\t\tie: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that XMLHttpRequest support is partial in Internet Explorer 11, but it is in fact properly supported\n\t\t\t\t\tkind: \"available\",\n\t\t\t\t\tversion: \"11\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t[\n\t\t// Caniuse reports that Safari 12.1 and iOS Safari 12.2 has partial support for Web Animations,\n\t\t// but they do not - They require enabling it as an experimental feature\n\t\t\"web-animation\",\n\t\t{\n\t\t\tsafari: rangeCorrection(\"safari\", \"unavailable\", `0`, \"13.4\"),\n\t\t\tios_saf: rangeCorrection(\"ios_saf\", \"unavailable\", `0`, \"13.4\")\n\t\t}\n\t],\n\t[\n\t\t\"es6-class\",\n\t\t{\n\t\t\tedge: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that Microsoft Edge has been supporting classes since v12, but it was prefixed until v13\n\t\t\t\t\tkind: \"prefixed\",\n\t\t\t\t\tversion: \"12\"\n\t\t\t\t}\n\t\t\t],\n\t\t\tios_saf: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that iOS Safari has been supporting classes since v9, but the implementation was only partial\n\t\t\t\t\tkind: \"partial_support\",\n\t\t\t\t\tversion: \"9\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that iOS Safari has been supporting classes since v9, but the implementation was only partial\n\t\t\t\t\tkind: \"partial_support\",\n\t\t\t\t\tversion: \"9.2\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that iOS Safari has been supporting classes since v9, but the implementation was only partial\n\t\t\t\t\tkind: \"partial_support\",\n\t\t\t\t\tversion: \"9.3\"\n\t\t\t\t}\n\t\t\t],\n\t\t\tsafari: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that Safari has been supporting classes since v9, but the implementation was only partial\n\t\t\t\t\tkind: \"partial_support\",\n\t\t\t\t\tversion: \"9\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that Safari has been supporting classes since v9, but the implementation was only partial\n\t\t\t\t\tkind: \"partial_support\",\n\t\t\t\t\tversion: \"9.1\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t[\n\t\t\"api.Element.classList\",\n\t\t{\n\t\t\tedge: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that Microsoft Edge v15 has only partial support for class-list since it doesn't support SVG elements,\n\t\t\t\t\t// but we don't want feature detections to return false for that browser\n\t\t\t\t\tkind: \"available\",\n\t\t\t\t\tversion: \"15\"\n\t\t\t\t}\n\t\t\t],\n\t\t\tie: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that IE 10 has only partial support for class-list since it doesn't support SVG elements,\n\t\t\t\t\t// but we don't want feature detections to return false for that browser\n\t\t\t\t\tkind: \"available\",\n\t\t\t\t\tversion: \"10\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that IE 11 has only partial support for class-list since it doesn't support SVG elements,\n\t\t\t\t\t// but we don't want feature detections to return false for that browser\n\t\t\t\t\tkind: \"available\",\n\t\t\t\t\tversion: \"11\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t[\"javascript.builtins.TypedArray.from\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.of\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.subarray\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.copyWithin\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.every\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.fill\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.filter\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.find\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.findIndex\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.forEach\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.indexOf\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.join\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.lastIndexOf\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.map\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.reduce\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.reduceRight\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.reverse\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.some\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.sort\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.toLocaleString\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.toString\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.slice\", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.includes\", TYPED_ARRAY_ES2016_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.keys\", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.values\", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.entries\", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.@@iterator\", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray.@@species\", TYPED_ARRAY_SPECIES_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.TypedArray\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Int8Array\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Int16Array\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Int32Array\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Float32Array\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Float64Array\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Uint8Array\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Uint8ClampedArray\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Uint16ClampedArray\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\"javascript.builtins.Uint32ClampedArray\", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],\n\t[\n\t\t\"javascript.builtins.String.@@iterator\",\n\t\t{\n\t\t\tandroid: rangeCorrection(\"chrome\", \"available\", `38`),\n\t\t\tchrome: rangeCorrection(\"chrome\", \"available\", `38`),\n\t\t\tand_chr: rangeCorrection(\"and_chr\", \"available\", `38`),\n\t\t\tedge: rangeCorrection(\"edge\", \"available\", `12`),\n\t\t\topera: rangeCorrection(\"opera\", \"available\", `25`),\n\t\t\top_mob: rangeCorrection(\"op_mob\", \"available\", `25`),\n\t\t\tfirefox: rangeCorrection(\"firefox\", \"available\", `36`),\n\t\t\tand_ff: rangeCorrection(\"and_ff\", \"available\", `36`),\n\t\t\tsafari: rangeCorrection(\"safari\", \"available\", `9`),\n\t\t\tios_saf: rangeCorrection(\"ios_saf\", \"available\", `9`),\n\t\t\tsamsung: rangeCorrection(\"samsung\", \"available\", `3`)\n\t\t}\n\t],\n\t[\n\t\t\"javascript.builtins.Symbol.asyncIterator\",\n\t\t{\n\t\t\tandroid: rangeCorrection(\"android\", \"available\", `63`),\n\t\t\tchrome: rangeCorrection(\"chrome\", \"available\", `63`),\n\t\t\tand_chr: rangeCorrection(\"and_chr\", \"available\", `63`),\n\t\t\topera: rangeCorrection(\"opera\", \"available\", `50`),\n\t\t\top_mob: rangeCorrection(\"op_mob\", \"available\", `50`),\n\t\t\tfirefox: rangeCorrection(\"firefox\", \"available\", `57`),\n\t\t\tand_ff: rangeCorrection(\"and_ff\", \"available\", `57`),\n\t\t\tsafari: rangeCorrection(\"safari\", \"available\", `11.1`),\n\t\t\tios_saf: rangeCorrection(\"ios_saf\", \"available\", `11.1`)\n\t\t}\n\t],\n\t[\n\t\t\"javascript.builtins.Array.@@species\",\n\t\t{\n\t\t\tandroid: rangeCorrection(\"android\", \"available\", `51`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Chrome v51\n\t\t\tchrome: rangeCorrection(\"chrome\", \"available\", `51`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Chrome for Android v51\n\t\t\tand_chr: rangeCorrection(\"and_chr\", \"available\", `51`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Edge v14\n\t\t\tedge: rangeCorrection(\"edge\", \"available\", `14`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Firefox v41\n\t\t\tfirefox: rangeCorrection(\"firefox\", \"available\", `41`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Firefox for Android v41\n\t\t\tand_ff: rangeCorrection(\"and_ff\", \"available\", `41`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Opera v38\n\t\t\topera: rangeCorrection(\"opera\", \"available\", `38`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Opera for Android v38\n\t\t\top_mob: rangeCorrection(\"op_mob\", \"available\", `38`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Safari v10\n\t\t\tsafari: rangeCorrection(\"safari\", \"available\", `10`),\n\t\t\t// MDN reports that it doesn't support Array.@@species, but it does and has done since Safari for iOS v10\n\t\t\tios_saf: rangeCorrection(\"ios_saf\", \"available\", `10`)\n\t\t}\n\t],\n\t[\n\t\t\"javascript.builtins.Date.@@toPrimitive\",\n\t\t{\n\t\t\tandroid: rangeCorrection(\"android\", \"available\", `48`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Chrome v48\n\t\t\tchrome: rangeCorrection(\"chrome\", \"available\", `48`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Chrome for Android v48\n\t\t\tand_chr: rangeCorrection(\"and_chr\", \"available\", `48`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done in all Edge versions\n\t\t\tedge: rangeCorrection(\"edge\", \"available\"),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Firefox v44\n\t\t\tfirefox: rangeCorrection(\"firefox\", \"available\", `44`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Firefox for Android v44\n\t\t\tand_ff: rangeCorrection(\"and_ff\", \"available\", `44`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Opera v35\n\t\t\topera: rangeCorrection(\"opera\", \"available\", `35`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Opera for Android v35\n\t\t\top_mob: rangeCorrection(\"op_mob\", \"available\", `35`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Safari v10\n\t\t\tsafari: rangeCorrection(\"safari\", \"available\", `10`),\n\t\t\t// MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Safari for iOS v10\n\t\t\tios_saf: rangeCorrection(\"ios_saf\", \"available\", `10`),\n\t\t\t// MDN reports that it doesn't support the Date.@@toPrimitive method, but it does and has done for all Samsung Internet versions\n\t\t\tsamsung: rangeCorrection(\"samsung\", \"available\")\n\t\t}\n\t],\n\t[\n\t\t\"fetch\",\n\t\t{\n\t\t\tedge: [\n\t\t\t\t{\n\t\t\t\t\t// Caniuse reports that Microsoft Edge has been supporting fetch since v14, but the implementation was quite unstable until v15\n\t\t\t\t\tkind: \"unavailable\",\n\t\t\t\t\tversion: \"14\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t[\n\t\t\"api.Window\",\n\t\t{\n\t\t\tchrome: rangeCorrection(\"chrome\", \"unavailable\", `0`, `18`),\n\t\t\tsafari: rangeCorrection(\"safari\", \"unavailable\", `0`, `5.1`),\n\t\t\tie: rangeCorrection(\"ie\", \"unavailable\", `0`, `7`),\n\t\t\topera: rangeCorrection(\"safari\", \"unavailable\", `0`, `11.1`)\n\t\t}\n\t],\n\t[\n\t\t\"javascript.builtins.String.matchAll\",\n\t\t{\n\t\t\tsamsung: rangeCorrection(\"samsung\", \"unavailable\", `0`, `9.4`)\n\t\t}\n\t],\n\t[\n\t\t\"resizeobserver\",\n\t\t{\n\t\t\tsafari: rangeCorrection(\"safari\", \"unavailable\", `0`)\n\t\t}\n\t]\n\t/* eslint-enable @typescript-eslint/naming-convention */\n];\n\n/**\n * A Map between caniuse features and corrections to apply (see above)\n */\nconst FEATURE_TO_BROWSER_DATA_CORRECTIONS_MAP = new Map<string, CaniuseBrowserCorrection>(FEATURE_TO_BROWSER_DATA_CORRECTIONS_INPUT);\n\n/**\n * Returns the input query, but extended with the given options\n */\nfunction extendQueryWith(query: string[], extendWith: string | string[]): string[] {\n\tconst normalizedExtendWith = Array.isArray(extendWith) ? extendWith : [extendWith];\n\treturn [...new Set([...query, ...normalizedExtendWith])];\n}\n\n/**\n * Normalizes the given Browserslist\n */\nexport function normalizeBrowserslist(browserslist: string | string[]): string[] {\n\tconst result = Browserslist(browserslist);\n\n\t// Caniuse only tracks the latest Browser version for Android-based browsers,\n\t// so we'll need to add the relevant details back in after normalizing the Browserslist\n\t// to make sure comparsions won't fail\n\tconst inputBrowserslist = Array.isArray(browserslist) ? browserslist : [browserslist];\n\n\tfor (const browser of [\"and_ff\", \"and_chr\", \"op_mini\"] as const) {\n\t\tconst versions = getSortedBrowserVersions(browser);\n\t\tfor (const entry of inputBrowserslist) {\n\t\t\tif (!entry.startsWith(browser)) continue;\n\t\t\tconst directMatch = entry.match(new RegExp(`${browser} (\\\\d+.*)`));\n\t\t\tif (directMatch != null) {\n\t\t\t\tconst candidate = `${browser} ${directMatch[1]}`;\n\t\t\t\tif (!result.includes(candidate)) {\n\t\t\t\t\tresult.push(candidate);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst greaterThanOrEqualsMatch = entry.match(new RegExp(`${browser} >= (\\\\d+)`));\n\n\t\t\t\tif (greaterThanOrEqualsMatch != null) {\n\t\t\t\t\tlet currentMajor = Number(greaterThanOrEqualsMatch[1]);\n\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tconst candidate = `${browser} ${currentMajor}`;\n\t\t\t\t\t\tif (!result.includes(candidate)) {\n\t\t\t\t\t\t\tresult.push(candidate);\n\t\t\t\t\t\t\tcurrentMajor++;\n\t\t\t\t\t\t\tif (Number(getClosestMatchingBrowserVersion(browser, String(currentMajor), versions)) <= currentMajor) break;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.sort();\n}\n\n/**\n * Returns the input query, but extended with 'unreleased versions'\n */\nfunction extendQueryWithUnreleasedVersions(query: string[], browsers: Iterable<CaniuseBrowser>): string[] {\n\treturn extendQueryWith(\n\t\tquery,\n\t\tArray.from(browsers).map(browser => `unreleased ${browser} versions`)\n\t);\n}\n\ninterface EcmaFeatureFilteringOptions {\n\tsyntaxOnly: boolean;\n\tfeatureFilter?(feature: string): boolean;\n}\n\ninterface BrowsersWithSupportOptions {\n\tfeatures: string[];\n}\n\n/**\n * Generates a Browserslist based on browser support for the given features\n */\nexport function browsersWithSupportForFeatures(...features: string[]): string[];\nexport function browsersWithSupportForFeatures(options: BrowsersWithSupportOptions): string[];\nexport function browsersWithSupportForFeatures(...args: [BrowsersWithSupportOptions] | string[]): string[] {\n\tconst [firstArg] = args;\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\tconst {features} = firstArg != null && typeof firstArg === \"object\" ? firstArg : {features: args as string[]};\n\n\tconst {query, browsers} = browserSupportForFeaturesCommon(\">=\", ...features);\n\treturn extendQueryWithUnreleasedVersions(query, browsers);\n}\n\n/**\n * Returns true if the given Browserslist supports the given EcmaVersion\n */\nexport function browserslistSupportsEcmaVersion(browserslist: string[], version: EcmaVersion, options?: Partial<EcmaFeatureFilteringOptions>): boolean {\n\tconst features = getFeaturesForEcmaVersion(version, options);\n\tif (features.length === 0) return true;\n\n\treturn browserslistSupportsFeatures(browserslist, ...features);\n}\n\nexport function getFeaturesForEcmaVersion(version: EcmaVersion, options?: Partial<EcmaFeatureFilteringOptions>): string[] {\n\tconst features = getFeaturesForEcmaVersionInner(version);\n\tconst filteredFirstPass = Boolean(options?.syntaxOnly) ? features.filter(feature => !feature.startsWith(\"javascript.builtins.\")) : features;\n\treturn typeof options?.featureFilter === \"function\" ? filteredFirstPass.filter(options.featureFilter) : filteredFirstPass;\n}\n\nfunction getFeaturesForEcmaVersionInner(version: EcmaVersion): string[] {\n\tswitch (version) {\n\t\tcase \"es3\":\n\t\t\t// ES3 is the lowest possible target and will always be treated as supported\n\t\t\treturn [];\n\n\t\tcase \"es5\":\n\t\t\treturn ES5_FEATURES;\n\n\t\tcase \"es2015\":\n\t\t\treturn ES2015_FEATURES;\n\n\t\tcase \"es2016\":\n\t\t\treturn ES2016_FEATURES;\n\n\t\tcase \"es2017\":\n\t\t\treturn ES2017_FEATURES;\n\n\t\tcase \"es2018\":\n\t\t\treturn ES2018_FEATURES;\n\n\t\tcase \"es2019\":\n\t\t\treturn ES2019_FEATURES;\n\n\t\tcase \"es2020\":\n\t\t\treturn ES2020_FEATURES;\n\n\t\tcase \"es2021\":\n\t\t\treturn ES2021_FEATURES;\n\n\t\tcase \"es2022\":\n\t\t\treturn ES2022_FEATURES;\n\n\t\tcase \"es2023\":\n\t\t\treturn ES2023_FEATURES;\n\n\t\tcase \"es2024\":\n\t\t\treturn ES2024_FEATURES;\n\t}\n}\n\n/**\n * Returns the appropriate Ecma version for the given Browserslist\n */\nexport function getAppropriateEcmaVersionForBrowserslist(browserslist: string[], options?: Partial<EcmaFeatureFilteringOptions>): EcmaVersion {\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2024\", options)) return \"es2024\";\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2023\", options)) return \"es2023\";\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2022\", options)) return \"es2022\";\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2021\", options)) return \"es2021\";\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2020\", options)) return \"es2020\";\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2019\", options)) return \"es2019\";\n\tif (browserslistSupportsEcmaVersion(browserslist, \"es2018\", options)) return \"es2018\";\n\telse if (browserslistSupportsEcmaVersion(browserslist, \"es2017\", options)) return \"es2017\";\n\telse if (browserslistSupportsEcmaVersion(browserslist, \"es2016\", options)) return \"es2016\";\n\telse if (browserslistSupportsEcmaVersion(browserslist, \"es2015\", options)) return \"es2015\";\n\telse if (browserslistSupportsEcmaVersion(browserslist, \"es5\", options)) return \"es5\";\n\telse return \"es3\";\n}\n\n/**\n * Generates a Browserslist based on browser support for the given ECMA version\n */\nexport function browsersWithSupportForEcmaVersion(version: EcmaVersion, options?: Partial<EcmaFeatureFilteringOptions>): string[] {\n\tswitch (version) {\n\t\tcase \"es3\":\n\t\t\treturn browsersWithoutSupportForFeatures(...getFeaturesForEcmaVersion(\"es5\", options));\n\t\tdefault:\n\t\t\treturn browsersWithSupportForFeatures(...getFeaturesForEcmaVersion(version, options));\n\t}\n}\n\n/**\n * Returns true if the given browserslist support all of the given features\n */\nexport function browserslistSupportsFeatures(browserslist: string[], ...features: string[]): boolean {\n\t// First, generate an ideal browserslist that would target the given features exactly\n\tconst normalizedIdealBrowserslist: string[] = normalizeBrowserslist(browsersWithSupportForFeatures(...features));\n\n\t// Now, normalize the input browserslist\n\tconst normalizedInputBrowserslist: string[] = normalizeBrowserslist(browserslist);\n\n\t// Now, compare the two and see if they align. If they do, the input browserslist *does* support all of the given features.\n\t// They align if all members of the input browserslist are included in the ideal browserslist\n\treturn normalizedInputBrowserslist.every(option => normalizedIdealBrowserslist.includes(option));\n}\n\n/**\n * Generates a Browserslist based on browsers that *doesn't* support the given features\n */\nexport function browsersWithoutSupportForFeatures(...features: string[]): string[];\nexport function browsersWithoutSupportForFeatures(options: BrowsersWithSupportOptions): string[];\nexport function browsersWithoutSupportForFeatures(...args: [BrowsersWithSupportOptions] | string[]): string[] {\n\tconst [firstArg] = args;\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\tconst {features} = firstArg != null && typeof firstArg === \"object\" ? firstArg : {features: args as string[]};\n\n\treturn browserSupportForFeaturesCommon(\"<\", ...features).query;\n}\n\n/**\n * Returns true if the given browser should be ignored. The data reported from Caniuse is a bit lacking.\n * For example, only the latest version of and_ff is reported, and since\n * android went to use Chromium for the WebView, it has only reported the latest Chromium version\n */\nfunction shouldIgnoreBrowser(browser: CaniuseBrowser, version: string): boolean {\n\treturn (\n\t\t// The data for the QQ browser is severely lacking and unreliable\n\t\tbrowser === \"and_qq\" ||\n\t\t// The data for the UC browser is severely lacking and unreliable\n\t\tbrowser === \"and_uc\" ||\n\t\t// The data for the Baidu browser is severely lacking and unreliable\n\t\tbrowser === \"baidu\" ||\n\t\t// The data for the KaiOS browser is severely lacking and unreliable\n\t\tbrowser === \"kaios\" ||\n\t\t(browser === \"android\" && gt(coerceToString(browser, version), coerceToString(browser, \"4.4.4\"))) ||\n\t\t(browser === \"op_mob\" && gt(coerceToString(browser, version), coerceToString(browser, \"12.1\")))\n\t);\n}\n\n/**\n * Normalizes the given ICaniuseLiteFeature\n */\nfunction getCaniuseLiteFeatureNormalized(stats: StatsByAgentID, featureName: string): CaniuseStatsNormalized {\n\t// Check if a correction exists for this browser\n\tconst featureCorrectionMatch = FEATURE_TO_BROWSER_DATA_CORRECTIONS_MAP.get(featureName);\n\n\tconst keys = Object.keys(stats) as (keyof StatsByAgentID)[];\n\tkeys.forEach(browser => {\n\t\tconst browserDict = stats[browser] as Mutable<(typeof stats)[typeof browser]> | undefined;\n\t\tif (browserDict == null) return;\n\n\t\tObject.entries(browserDict).forEach(([version, support]: [string, string]) => {\n\t\t\tconst versionMatch = version.match(NORMALIZE_BROWSER_VERSION_REGEXP);\n\t\t\tconst normalizedVersion = versionMatch == null ? version : (versionMatch[1] ?? version);\n\n\t\t\tlet supportKind: CaniuseSupportKind;\n\n\t\t\tif (support === \"available\" || support === \"unavailable\" || support === \"partial_support\" || support === \"prefixed\") {\n\t\t\t\tsupportKind = support;\n\t\t\t} else if (support.startsWith(\"y\")) {\n\t\t\t\tsupportKind = \"available\";\n\t\t\t} else if (support.startsWith(\"n\")) {\n\t\t\t\tsupportKind = \"unavailable\";\n\t\t\t} else if (support.startsWith(\"a\")) {\n\t\t\t\tsupportKind = \"partial_support\";\n\t\t\t} else {\n\t\t\t\tsupportKind = \"prefixed\";\n\t\t\t}\n\n\t\t\t// Delete the rewritten version\n\t\t\tif (version !== normalizedVersion) {\n\t\t\t\tdelete browserDict[version];\n\t\t\t}\n\t\t\tif (support !== supportKind) {\n\t\t\t\tbrowserDict[normalizedVersion] = supportKind;\n\t\t\t}\n\n\t\t\t// If a feature correction exists for this feature, apply applicable corrections\n\t\t\tif (featureCorrectionMatch != null) {\n\t\t\t\t// Check if the browser has some corrections\n\t\t\t\tconst browserMatch = featureCorrectionMatch[browser as keyof CaniuseStatsNormalized];\n\t\t\t\tif (browserMatch != null) {\n\t\t\t\t\t// Apply all corrections\n\t\t\t\t\tbrowserMatch.forEach(correction => {\n\t\t\t\t\t\tbrowserDict[correction.version] = correction.kind;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n\n\treturn stats as CaniuseStatsNormalized;\n}\n\n/**\n * Gets the support from caniuse for the given feature\n */\nfunction getCaniuseFeatureSupport(feature: string): CaniuseStatsNormalized {\n\tconst packedFeature = caniuseFeatures[feature];\n\tif (packedFeature == null) {\n\t\tthrow new TypeError(`The given feature: '${feature}' is unknown. It must be a valid Caniuse or MDN feature!`);\n\t}\n\n\tconst rawStats = caniuseFeature(packedFeature).stats;\n\n\tfor (const browser of Object.keys(rawStats)) {\n\t\tconst browserDict = rawStats[browser] as Mutable<(typeof rawStats)[typeof browser]> | undefined;\n\t\tif (browserDict == null) continue;\n\n\t\tfor (const version of Object.keys(browserDict)) {\n\t\t\tif (shouldIgnoreBrowser(browser as keyof CaniuseStatsNormalized, version)) {\n\t\t\t\tdelete browserDict[version];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn getCaniuseLiteFeatureNormalized(rawStats, feature);\n}\n\n/**\n * Returns true if the given feature is a Caniuse feature\n */\nfunction isCaniuseFeature(feature: string): boolean {\n\treturn caniuseFeatures[feature] != null;\n}\n\n/**\n * Returns true if the given feature is a MDN feature\n */\nfunction isMdnFeature(feature: string): boolean {\n\treturn objectPath.get(compatData, feature) != null;\n}\n\n/**\n * Asserts that the given feature is a valid Caniuse or MDN feature name\n */\nfunction assertKnownFeature(feature: string): void {\n\tif (!isCaniuseFeature(feature) && !isMdnFeature(feature)) {\n\t\tthrow new TypeError(`The given feature: '${feature}' is unknown. It must be a valid Caniuse or MDN feature!`);\n\t}\n}\n\nfunction normalizeFeature(feature: string): string {\n\tif (feature in CANIUSE_TO_MDN_FEATURE_MAP) {\n\t\treturn CANIUSE_TO_MDN_FEATURE_MAP[feature as keyof typeof CANIUSE_TO_MDN_FEATURE_MAP];\n\t}\n\n\treturn feature;\n}\n\n/**\n * Gets the feature support for the given feature\n */\nfunction getFeatureSupport(feature: string): CaniuseStatsNormalized {\n\tconst normalizedFeature = normalizeFeature(feature);\n\t// First check if the cache has a match and return it if so\n\tconst cacheHit = featureToCaniuseStatsCache.get(normalizedFeature);\n\tif (cacheHit != null) return cacheHit;\n\n\t// Assert that the feature is in fact known\n\tassertKnownFeature(normalizedFeature);\n\n\tconst result = isMdnFeature(normalizedFeature) ? getMdnFeatureSupport(normalizedFeature) : getCaniuseFeatureSupport(normalizedFeature);\n\n\t// Store it in the cache before returning it\n\tfeatureToCaniuseStatsCache.set(normalizedFeature, result);\n\treturn result;\n}\n\n/**\n * Gets the support from caniuse for the given feature\n */\nfunction getMdnFeatureSupport(feature: string): CaniuseStatsNormalized {\n\tconst match = objectPath.get(compatData, feature) as Mdn;\n\tconst supportMap = match.__compat.support;\n\n\tconst formatBrowser = (mdnBrowser: MdnBrowserName, caniuseBrowser: CaniuseBrowser): Record<string, CaniuseSupportKind> => {\n\t\tconst versionMap = supportMap[mdnBrowser] as MaybeArray<MdnSupportDict> | undefined;\n\t\tconst versionAdded =\n\t\t\tversionMap == null\n\t\t\t\t? false\n\t\t\t\t: Array.isArray(versionMap)\n\t\t\t\t\t? // If there are multiple entries, take the one that hasn't been removed yet, if any\n\t\t\t\t\t\t(() => {\n\t\t\t\t\t\t\tconst versionStillInBrowser = versionMap.find(element => element.version_removed == null);\n\t\t\t\t\t\t\treturn versionStillInBrowser?.version_added == null ? false : versionStillInBrowser.version_added;\n\t\t\t\t\t\t})()\n\t\t\t\t\t: versionMap.version_added;\n\n\t\tconst dict: Record<string, CaniuseSupportKind> = {};\n\t\tconst supportedSince: string | null = versionAdded === false ? null : versionAdded === true ? getOldestVersionOfBrowser(caniuseBrowser) : versionAdded;\n\n\t\tgetSortedBrowserVersionsWithLeadingVersion(caniuseBrowser, typeof versionAdded === \"string\" ? versionAdded : undefined).forEach(version => {\n\t\t\t// If the features has never been supported, mark the feature as unavailable\n\t\t\tif (supportedSince == null) {\n\t\t\t\tdict[version] = \"unavailable\";\n\t\t\t} else {\n\t\t\t\tdict[version] =\n\t\t\t\t\tversion === \"TP\" || version === \"all\" || gte(coerceToString(caniuseBrowser, version), coerceToString(caniuseBrowser, supportedSince)) ? \"available\" : \"unavailable\";\n\t\t\t}\n\t\t});\n\t\treturn dict;\n\t};\n\n\tconst stats: CaniuseStatsNormalized = {\n\t\t/* eslint-disable @typescript-eslint/naming-convention */\n\t\tand_chr: formatBrowser(\"chrome_android\", \"and_chr\"),\n\t\tchrome: formatBrowser(\"chrome\", \"chrome\"),\n\t\tand_ff: formatBrowser(\"firefox_android\", \"and_ff\"),\n\t\tandroid: formatBrowser(\"webview_android\", \"android\"),\n\t\tbb: {},\n\t\tand_qq: {},\n\t\tand_uc: {},\n\t\tkaios: {},\n\t\tbaidu: {},\n\t\tedge: formatBrowser(\"edge\", \"edge\"),\n\t\tsamsung: formatBrowser(\"samsunginternet_android\", \"samsung\"),\n\t\tie: formatBrowser(\"ie\", \"ie\"),\n\t\tie_mob: formatBrowser(\"ie\", \"ie_mob\"),\n\t\tsafari: formatBrowser(\"safari\", \"safari\"),\n\t\tios_saf: formatBrowser(\"safari_ios\", \"ios_saf\"),\n\t\topera: formatBrowser(\"opera\", \"opera\"),\n\t\top_mini: {},\n\t\top_mob: {},\n\t\tfirefox: formatBrowser(\"firefox\", \"firefox\")\n\t\t/* eslint-enable @typescript-eslint/naming-convention */\n\t};\n\treturn getCaniuseLiteFeatureNormalized(stats, feature);\n}\n\n/**\n * Gets the first version that matches the given CaniuseSupportKind\n */\nfunction getFirstVersionWithSupportKind(kind: CaniuseSupportKind, stats: Record<string, CaniuseSupportKind>): string | undefined {\n\t// Sort all keys of the object\n\tconst sortedKeys = Object.keys(stats).sort(compareVersions);\n\n\tfor (const key of sortedKeys) {\n\t\tif (stats[key] === kind) {\n\t\t\treturn key;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Sorts the given browserslist. Ensures that 'not' expressions come last\n */\nfunction sortBrowserslist(a: string, b: string): number {\n\tif (a.startsWith(\"not\") && !b.startsWith(\"not\")) return 1;\n\tif (!a.startsWith(\"not\") && b.startsWith(\"not\")) return -1;\n\treturn 0;\n}\n\n/**\n * Gets a Map between browser names and the first version of them that supported the given feature\n */\nexport function getFirstVersionsWithFullSupport(feature: string): Map<CaniuseBrowser, string> {\n\tconst normalizedFeature = normalizeFeature(feature);\n\tconst support = getFeatureSupport(normalizedFeature);\n\t// A map between browser names and their required versions\n\tconst browserMap = new Map<CaniuseBrowser, string>();\n\tconst entries = Object.entries(support) as [CaniuseBrowser, Record<string, CaniuseSupportKind>][];\n\tentries.forEach(([browser, stats]) => {\n\t\tconst fullSupportVersion = getFirstVersionWithSupportKind(\"available\", stats);\n\t\tif (fullSupportVersion != null) {\n\t\t\tbrowserMap.set(browser, fullSupportVersion);\n\t\t}\n\t});\n\treturn browserMap;\n}\n\n/**\n * Gets the Cache key for the given combination of a comparison operator and any amount of features\n */\nfunction getBrowserSupportForFeaturesCacheKey(comparisonOperator: ComparisonOperator, features: string[]): string {\n\treturn `${comparisonOperator}.${features.sort().join(\",\")}`;\n}\n\n/**\n * Common logic for the functions that generate browserslists based on feature support\n */\nfunction browserSupportForFeaturesCommon(comparisonOperator: ComparisonOperator, ...features: string[]): BrowserSupportForFeaturesCommonResult {\n\tconst normalizedFeatures = features.map(normalizeFeature);\n\tconst cacheKey = getBrowserSupportForFeaturesCacheKey(comparisonOperator, normalizedFeatures);\n\n\t// First check if the cache has a hit and return it if so\n\tconst cacheHit = browserSupportForFeaturesCache.get(cacheKey);\n\tif (cacheHit != null) {\n\t\treturn cacheHit;\n\t}\n\n\t// All of the generated browser maps\n\tconst browserMaps: Map<CaniuseBrowser, string>[] = [];\n\n\tfor (const normalizedFeature of normalizedFeatures) {\n\t\tconst support = getFeatureSupport(normalizedFeature);\n\n\t\t// A map between browser names and their required versions\n\t\tconst browserMap = new Map<CaniuseBrowser, string>();\n\t\tconst entries = Object.entries(support) as [CaniuseBrowser, Record<string, CaniuseSupportKind>][];\n\t\tentries.forEach(([browser, stats]) => {\n\t\t\tconst fullSupportVersion = getFirstVersionWithSupportKind(\"available\", stats);\n\t\t\tconst partialSupportVersion = getFirstVersionWithSupportKind(\"partial_support\", stats);\n\t\t\tlet versionToSet: string | undefined;\n\n\t\t\tif (fullSupportVersion != null) {\n\t\t\t\tversionToSet = fullSupportVersion;\n\t\t\t}\n\n\t\t\t// Otherwise, check if partial support exists and should be allowed\n\t\t\tif (partialSupportVersion != null) {\n\t\t\t\t// Get all partial support allowances for this specific feature\n\t\t\t\tconst partialSupportMatch = PARTIAL_SUPPORT_ALLOWANCES.get(normalizedFeature);\n\n\t\t\t\t// Check if partial support exists for the browser. // If no full supported version exists or if the partial supported version has a lower version number than the full supported one, use that one instead\n\t\t\t\tif (\n\t\t\t\t\tpartialSupportMatch != null &&\n\t\t\t\t\t(partialSupportMatch === \"*\" || partialSupportMatch.includes(browser)) &&\n\t\t\t\t\t(fullSupportVersion == null || compareVersions(partialSupportVersion, fullSupportVersion) < 0)\n\t\t\t\t) {\n\t\t\t\t\tversionToSet = partialSupportVersion;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (versionToSet == null) {\n\t\t\t\t// Apply additional checks depending on the comparison operator\n\t\t\t\tswitch (comparisonOperator) {\n\t\t\t\t\tcase \"<\":\n\t\t\t\t\tcase \"<=\":\n\t\t\t\t\t\t// Add all browsers with no support whatsoever, or those that require prefixing or flags\n\t\t\t\t\t\tversionToSet = \"-1\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (versionToSet != null) {\n\t\t\t\tbrowserMap.set(browser, versionToSet);\n\t\t\t}\n\t\t});\n\n\t\tbrowserMaps.push(browserMap);\n\t}\n\n\t// Now, remove all browsers that isn't part of all generated browser maps\n\tfor (const browserMap of browserMaps) {\n\t\tfor (const browser of browserMap.keys()) {\n\t\t\tif (!browserMaps.every(map => map.has(browser))) {\n\t\t\t\t// Delete the browser if it isn't included in all of the browser maps\n\t\t\t\tbrowserMap.delete(browser);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Now, prepare a combined browser map\n\tconst combinedBrowserMap = new Map<CaniuseBrowser, string>();\n\n\tfor (const browserMap of browserMaps) {\n\t\tfor (const [browser, version] of browserMap.entries()) {\n\t\t\t// Take the existing entry from the combined map\n\t\t\tconst existingVersion = combinedBrowserMap.get(browser);\n\t\t\t// The browser should be set in the map if it has no entry already\n\t\t\tconst shouldSet = existingVersion !== \"-1\" && (existingVersion == null || version === \"-1\" || compareVersions(version, existingVersion) >= 0);\n\n\t\t\tif (shouldSet) {\n\t\t\t\t// Set the version in the map\n\t\t\t\tcombinedBrowserMap.set(browser, version);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Finally, generate a string array of the browsers\n\t// Make sure that 'not' expressions come last\n\tconst query: string[] = ([] as string[]).concat\n\t\t.apply(\n\t\t\t[],\n\t\t\tArray.from(combinedBrowserMap.entries()).map(([browser, version]) => {\n\t\t\t\t// The version is not a number, so we can't do comparisons on it.\n\t\t\t\tif (isNaN(parseFloat(version))) {\n\t\t\t\t\tswitch (comparisonOperator) {\n\t\t\t\t\t\tcase \"<\":\n\t\t\t\t\t\tcase \"<=\": {\n\t\t\t\t\t\t\tconst previousVersion = getPreviousVersionOfBrowser(browser, version);\n\t\t\t\t\t\t\treturn [`not ${browser} ${version}`, ...(previousVersion == null ? [] : [`${browser} ${comparisonOperator} ${previousVersion}`])];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase \">\":\n\t\t\t\t\t\tcase \">=\": {\n\t\t\t\t\t\t\tconst nextVersion = getNextVersionOfBrowser(browser, version);\n\t\t\t\t\t\t\treturn [`${browser} ${version}`, ...(nextVersion == null ? [] : [`${browser} ${comparisonOperator} ${nextVersion}`])];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn parseInt(version) === -1\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t`${comparisonOperator === \">\" || comparisonOperator === \">=\" ? \"not \" : \"\"}${browser} ${browser === \"op_mini\" ? \"all\" : \"> 0\"}`,\n\t\t\t\t\t\t\t`${comparisonOperator === \">\" || comparisonOperator === \">=\" ? \"not \" : \"\"}unreleased ${browser} versions`\n\t\t\t\t\t\t]\n\t\t\t\t\t: [`${browser} ${comparisonOperator} ${version}`];\n\t\t\t})\n\t\t)\n\t\t.sort(sortBrowserslist);\n\tconst returnObject = {\n\t\tquery,\n\t\tbrowsers: new Set(combinedBrowserMap.keys())\n\t};\n\n\t// Store it in the cache before returning it\n\tbrowserSupportForFeaturesCache.set(cacheKey, returnObject);\n\treturn returnObject;\n}\n\n/**\n * Gets the matching CaniuseBrowser for the given UseragentBrowser. Not all are supported, so it may return undefined\n */\nfunction getCaniuseBrowserForUseragentBrowser(parser: UaParserWrapper): Partial<VersionedCaniuseBrowser> {\n\tconst browser = parser.getBrowser();\n\tconst device = parser.getDevice();\n\tconst os = parser.getOS();\n\tconst engine = parser.getEngine();\n\n\t// If the OS is iOS, it is actually Safari that drives the WebView\n\tif (os.name === \"iOS\") {\n\t\t// Opera Mini with the Presto runtime actually works around\n\t\t// the restrictions os the Safari WebView\n\t\tif (browser.name === \"Opera Mini\" && engine.name === \"Presto\") {\n\t\t\treturn {\n\t\t\t\tbrowser: \"op_mini\",\n\t\t\t\tversion: browser.version\n\t\t\t};\n\t\t}\n\n\t\t// In all other cases, it is always Safari driving the WebView\n\t\treturn {\n\t\t\tbrowser: \"ios_saf\",\n\t\t\tversion: os.version ?? browser.version\n\t\t};\n\t}\n\n\t// First, if it is a Blackberry device, it will always be the 'bb' browser\n\tif (device.vendor === \"BlackBerry\" || os.name === \"BlackBerry\") {\n\t\treturn {\n\t\t\tbrowser: \"bb\",\n\t\t\tversion: browser.version\n\t\t};\n\t}\n\n\t// For platforms where the HeyTapBrowser doesn't report which Chrome version\n\t// it is based on, we'll have to rely on knowledge from similar user agent strings.\n\t// as far as we know, HeyTapBrowser on non-iOS is always based on Chrome 70 or 77,\n\t// seemingly at random. So we'll have to assume Chrome 70 here.\n\tif (browser.name === \"HeyTapBrowser\" && engine.name === \"WebKit\") {\n\t\treturn {\n\t\t\tbrowser: \"chrome\",\n\t\t\tversion: \"70\"\n\t\t};\n\t}\n\n\t// Unfortunately, since Caniuse doesn't support PaleMoon,\n\t// we will have to remap it to its closest equivalent Firefox\n\t// version (which it is similar to and a fork of).\n\t// This is less than ideal, but unfortunately a requirement for the time being\n\tif (browser.name === \"PaleMoon\" && engine.name === \"Goanna\" && browser.version != null) {\n\t\tconst semver = ensureSemver(undefined, browser.version);\n\n\t\t// The data comes from this table: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)#Releases\n\t\tif (semver != null && lte(semver, \"5.0.0\")) {\n\t\t\treturn {\n\t\t\t\tbrowser: \"firefox\",\n\t\t\t\tversion: \"2\"\n\t\t\t};\n\t\t}\n\n\t\t// Between these two versions, the version numbers followed Firefox/Gecko\n\t\telse if (semver != null && lte(semver, \"24.0.0\")) {\n\t\t\treturn {\n\t\t\t\tbrowser: \"firefox\",\n\t\t\t\tversion: browser.version\n\t\t\t};\n\t\t}\n\n\t\t// It kept staying at Firefox 24 for all we know\n\t\telse if (semver != null && lt(semver, \"27.0.0\")) {\n\t\t\treturn {\n\t\t\t\tbrowser: \"firefox\",\n\t\t\t\tversion: \"24.0.0\"\n\t\t\t};\n\t\t}\n\n\t\t// Then, from v27, it was based on a re-fork of Firefox 38.\n\t\t// Unfortunately, we don't have fresh data as for the versions\n\t\t// in between 27 and 29, so we'll have to stay at vers