Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 57 additions & 48 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import browserslist from 'browserslist';
import semver from 'semver';
import UAParser from 'ua-parser-js';
import browserslist from 'browserslist'
import semver from 'semver'
import { UAParser } from 'ua-parser-js'

// @see https://github.com/ai/browserslist#browsers

Expand All @@ -23,15 +23,21 @@ const browserNameMap: Record<string, string> = {
and_uc: 'UCAndroid',
}

function resolveUserAgent(uaString: string): { family: string | null, version: string | null } {
const parsedUA = UAParser(uaString)
const parsedBrowserVersion = semverify(parsedUA.browser.version)
const parsedOSVersion = semverify(parsedUA.os.version)
const parsedEngineVersion = semverify(parsedUA.engine.version)
function resolveUserAgent(uaString: string): {
family: string | null
version: string | null
} {
const parsedUA = new UAParser(uaString)
const browser = parsedUA.getBrowser()
const os = parsedUA.getOS()
const engine = parsedUA.getEngine()

const parsedBrowserVersion = semverify(browser.version)
const parsedOSVersion = semverify(os.version)
const parsedEngineVersion = semverify(engine.version)

// Case A: For Safari on iOS, the use the browser version
if (
parsedUA.browser.name === 'Safari' && parsedUA.os.name === 'iOS') {
if (browser.name === 'Safari' && os.name === 'iOS') {
return {
family: 'iOS',
version: parsedBrowserVersion,
Expand All @@ -43,84 +49,87 @@ function resolveUserAgent(uaString: string): { family: string | null, version: s
// version. This is based on the assumption that the
// underlying Safari Engine used will be *atleast* equal
// to the iOS version it's running on.
if (parsedUA.os.name === 'iOS') {
if (os.name === 'iOS') {
return {
family: 'iOS',
version: parsedOSVersion
version: parsedOSVersion,
}
}

const device = parsedUA.getDevice()
if (
(parsedUA.browser.name === 'Opera' && parsedUA.device.type === 'mobile') ||
parsedUA.browser.name === 'Opera Mobi'
(browser.name === 'Opera' && device.type === 'mobile') ||
browser.name === 'Opera Mobi'
) {
return {
family: 'OperaMobile',
version: parsedBrowserVersion
version: parsedBrowserVersion,
}
}

if (parsedUA.browser.name === 'Samsung Browser') {
if (browser.name === 'Samsung Internet') {
return {
family: 'Samsung',
version: parsedBrowserVersion
version: parsedBrowserVersion,
}
}

if (parsedUA.browser.name === 'IE') {
if (browser.name === 'IE') {
return {
family: 'Explorer',
version: parsedBrowserVersion
version: parsedBrowserVersion,
}
}

if (parsedUA.browser.name === 'IEMobile') {
if (browser.name === 'IEMobile') {
return {
family: 'ExplorerMobile',
version: parsedBrowserVersion
version: parsedBrowserVersion,
}
}

// Use engine version for gecko-based browsers
if (parsedUA.engine.name === 'Gecko') {
if (engine.name === 'Gecko') {
return {
family: 'Firefox',
version: parsedEngineVersion
version: parsedEngineVersion,
}
}

// Use engine version for blink-based browsers
if (parsedUA.engine.name === 'Blink') {
if (engine.name === 'Blink') {
return {
family: 'Chrome',
version: parsedEngineVersion
version: parsedEngineVersion,
}
}

// Chrome based browsers pre-blink (WebKit)
if (
parsedUA.browser.name &&
['Chrome', 'Chromium', 'Chrome WebView', 'Chrome Headless'].includes(parsedUA.browser.name)
browser.name &&
['Chrome', 'Chromium', 'Chrome WebView', 'Chrome Headless'].includes(
browser.name
)
) {
return {
family: 'Chrome',
version: parsedBrowserVersion
version: parsedBrowserVersion,
}
}

if (parsedUA.browser.name === 'Android Browser') {
if (browser.name === 'Android Browser') {
// Versions prior to Blink were based
// on the OS version. Only after this
// did android start using system chrome for web-views
return {
family: 'Android',
version: parsedOSVersion
version: parsedOSVersion,
}
}

return {
family: parsedUA.browser.name || null,
version: parsedBrowserVersion
family: browser.name || null,
version: parsedBrowserVersion,
}
}

Expand Down Expand Up @@ -169,7 +178,9 @@ function normalizeQuery(query: string) {
return normalizedQuery
}

const parseBrowsersList = (browsersList: string[]): { family: string, version: string | null }[] => {
const parseBrowsersList = (
browsersList: string[]
): { family: string; version: string | null }[] => {
const browsers = browsersList
.map((browser) => {
const [name, version] = browser.split(' ')
Expand Down Expand Up @@ -203,7 +214,11 @@ const parseBrowsersList = (browsersList: string[]): { family: string, version: s
return browsers.flat()
}

const compareBrowserSemvers = (versionA: string, versionB: string, options: Options) => {
const compareBrowserSemvers = (
versionA: string,
versionB: string,
options: Options
) => {
const semverifiedA = semverify(versionA)
const semverifiedB = semverify(versionB)

Expand All @@ -228,11 +243,11 @@ const compareBrowserSemvers = (versionA: string, versionB: string, options: Opti
}

type Options = {
browsers?: string[],
env?: string,
path?: string,
ignoreMinor?: boolean,
ignorePatch?: boolean,
browsers?: string[]
env?: string
path?: string
ignoreMinor?: boolean
ignorePatch?: boolean
allowHigherVersions?: boolean
}

Expand All @@ -251,10 +266,8 @@ const matchesUA = (uaString: string, opts: Options = {}) => {
path: opts.path || process.cwd(),
})


const parsedBrowsers = parseBrowsersList(browsers)


const resolvedUserAgent = resolveUserAgent(uaString)

const options = {
Expand All @@ -268,17 +281,13 @@ const matchesUA = (uaString: string, opts: Options = {}) => {
if (!resolvedUserAgent.version) return false
if (!browser.version) return false


return (
browser.family.toLowerCase() ===
resolvedUserAgent.family.toLocaleLowerCase() &&
resolvedUserAgent.family.toLocaleLowerCase() &&
compareBrowserSemvers(resolvedUserAgent.version, browser.version, options)
)
})
}

export {
matchesUA,
resolveUserAgent,
normalizeQuery,
}
export { matchesUA, resolveUserAgent, normalizeQuery }

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"dependencies": {
"semver": "^7.3.5",
"ua-parser-js": "^1.0.32"
"ua-parser-js": "^2.0.6"
},
"peerDependencies": {
"browserslist": "^4.0.0"
Expand All @@ -37,7 +37,6 @@
"@types/jest": "^29.1.2",
"@types/node": "^18.11.0",
"@types/semver": "^7.3.12",
"@types/ua-parser-js": "^0.7.36",
"@types/useragent": "^2.3.1",
"babel-cli": "^6.26.0",
"browserslist": "^4.19.1",
Expand Down
32 changes: 23 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1308,11 +1308,6 @@
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==

"@types/ua-parser-js@^0.7.36":
version "0.7.36"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz#9bd0b47f26b5a3151be21ba4ce9f5fa457c5f190"
integrity sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==

"@types/useragent@^2.3.1":
version "2.3.1"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/useragent/-/useragent-2.3.1.tgz#c971243faa04f50df399da35d77538ab5fabae20"
Expand Down Expand Up @@ -2053,6 +2048,11 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"

detect-europe-js@^0.1.2:
version "0.1.2"
resolved "https://artifactory.klarna.net/artifactory/api/npm/v-npm-production/detect-europe-js/-/detect-europe-js-0.1.2.tgz#aa76642e05dae786efc2e01a23d4792cd24c7b88"
integrity sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==

detect-indent@^4.0.0:
version "4.0.0"
resolved "https://packages.atlassian.com/api/npm/npm-remote/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
Expand Down Expand Up @@ -2672,6 +2672,11 @@ is-primitive@^2.0.0:
resolved "https://packages.atlassian.com/api/npm/npm-remote/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
integrity sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==

is-standalone-pwa@^0.1.1:
version "0.1.1"
resolved "https://artifactory.klarna.net/artifactory/api/npm/v-npm-production/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz#7a1b0459471a95378aa0764d5dc0a9cec95f2871"
integrity sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==

is-stream@^2.0.0:
version "2.0.1"
resolved "https://packages.atlassian.com/api/npm/npm-remote/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
Expand Down Expand Up @@ -4137,10 +4142,19 @@ typescript@^4.8.4:
resolved "https://packages.atlassian.com/api/npm/npm-remote/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6"
integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==

ua-parser-js@^1.0.32:
version "1.0.32"
resolved "https://packages.atlassian.com/api/npm/npm-remote/ua-parser-js/-/ua-parser-js-1.0.32.tgz#786bf17df97de159d5b1c9d5e8e9e89806f8a030"
integrity sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==
ua-is-frozen@^0.1.2:
version "0.1.2"
resolved "https://artifactory.klarna.net/artifactory/api/npm/v-npm-production/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz#bfbc5f06336e379590e36beca444188c7dc3a7f3"
integrity sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==

ua-parser-js@^2.0.6:
version "2.0.6"
resolved "https://artifactory.klarna.net/artifactory/api/npm/v-npm-production/ua-parser-js/-/ua-parser-js-2.0.6.tgz#1dd221f7f2a27357c6a342296852f6391d77d4f0"
integrity sha512-EmaxXfltJaDW75SokrY4/lXMrVyXomE/0FpIIqP2Ctic93gK7rlme55Cwkz8l3YZ6gqf94fCU7AnIkidd/KXPg==
dependencies:
detect-europe-js "^0.1.2"
is-standalone-pwa "^0.1.1"
ua-is-frozen "^0.1.2"

unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
Expand Down