ua.js (3107B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const BROWSERS = [ 8 { 9 name: "Firefox", 10 mustContain: new RegExp(`(?:Firefox|FxiOS)\/(${getVersionRegex(1, 1)})`), 11 }, 12 { 13 name: "Opera", 14 mustContain: new RegExp(`(?:OPR|Opera)\/(${getVersionRegex(1, 1)})`), 15 }, 16 { 17 name: "Safari", 18 mustContain: new RegExp(`Version\/(${getVersionRegex(1, 1)}).+Safari`), 19 mustNotContain: new RegExp("Chrome|Chromium"), 20 }, 21 { 22 name: "Edge", 23 mustContain: new RegExp(`Edge\/(${getVersionRegex(0, 1)})`), 24 }, 25 { 26 name: "Chrome", 27 mustContain: new RegExp(`(?:Chrome|CriOS)\/(${getVersionRegex(1, 1)})`), 28 }, 29 { 30 name: "IE", 31 mustContain: new RegExp(`MSIE (${getVersionRegex(1, 1)})`), 32 }, 33 ]; 34 35 const OSES = [ 36 { 37 name: "iOS", 38 minMinorVersionCount: 0, 39 mustContain: new RegExp(`CPU iPhone OS (${getVersionRegex(0, 2)})`), 40 }, 41 { 42 name: "iPadOS", 43 minMinorVersionCount: 0, 44 mustContain: new RegExp(`CPU OS (${getVersionRegex(0, 2)})`), 45 }, 46 { 47 name: "Windows Phone", 48 minMinorVersionCount: 1, 49 mustContain: new RegExp(`Windows Phone (${getVersionRegex(1, 2)})`), 50 }, 51 { 52 name: "Chrome OS", 53 minMinorVersionCount: 1, 54 mustContain: new RegExp(`CrOS .+ (${getVersionRegex(1, 2)})`), 55 }, 56 { 57 name: "Android", 58 minMinorVersionCount: 0, 59 mustContain: new RegExp(`Android (${getVersionRegex(0, 2)})`), 60 }, 61 { 62 name: "Windows NT", 63 minMinorVersionCount: 1, 64 mustContain: new RegExp(`Windows NT (${getVersionRegex(1, 2)})`), 65 }, 66 { 67 name: "Mac OSX", 68 minMinorVersionCount: 1, 69 mustContain: new RegExp(`Intel Mac OS X (${getVersionRegex(1, 2)})`), 70 }, 71 { 72 name: "Linux", 73 mustContain: new RegExp("Linux"), 74 }, 75 ]; 76 77 function getVersionRegex(minMinorVersionCount, maxMinorVersionCount) { 78 return `\\d+(?:[._][0-9a-z]+){${minMinorVersionCount},${maxMinorVersionCount}}`; 79 } 80 81 function detect(ua, dataset) { 82 for (const { 83 name, 84 mustContain, 85 mustNotContain, 86 minMinorVersionCount, 87 } of dataset) { 88 const result = mustContain.exec(ua); 89 90 if (!result) { 91 continue; 92 } 93 94 if (mustNotContain && mustNotContain.test(ua)) { 95 continue; 96 } 97 98 let version = null; 99 100 if (result && result.length === 2) { 101 // Remove most minor version if that expresses 0. 102 let parts = result[1].match(/([0-9a-z]+)/g); 103 parts = parts.reverse(); 104 const validVersionIndex = parts.findIndex( 105 part => parseInt(part, 10) !== 0 106 ); 107 if (validVersionIndex !== -1) { 108 parts = parts.splice(validVersionIndex); 109 for (let i = 0; i < minMinorVersionCount + 1 - parts.length; i++) { 110 parts.unshift(0); 111 } 112 } 113 version = parts.reverse().join("."); 114 } 115 116 return { name, version }; 117 } 118 119 return null; 120 } 121 122 function parseUserAgent(ua) { 123 return { 124 browser: detect(ua, BROWSERS), 125 os: detect(ua, OSES), 126 }; 127 } 128 129 module.exports = { parseUserAgent };