vuetify-nuxt-module
Version:
Zero-Config Nuxt Module for Vuetify
181 lines (180 loc) • 5.91 kB
JavaScript
import process from "node:process";
export class BrowserInfo {
constructor(name, version, os) {
this.name = name;
this.version = version;
this.os = os;
}
type = "browser";
}
export class NodeInfo {
constructor(version) {
this.version = version;
}
type = "node";
name = "node";
os = process.platform;
}
export class SearchBotDeviceInfo {
constructor(name, version, os, bot) {
this.name = name;
this.version = version;
this.os = os;
this.bot = bot;
}
type = "bot-device";
}
export class BotInfo {
type = "bot";
bot = true;
// NOTE: deprecated test name instead
name = "bot";
version = null;
os = null;
}
export class ReactNativeInfo {
type = "react-native";
name = "react-native";
version = null;
os = null;
}
const SEARCHBOX_UA_REGEX = /alexa|bot|crawl(er|ing)|facebookexternalhit|feedburner|google web preview|nagios|postrank|pingdom|slurp|spider|yahoo!|yandex/;
const SEARCHBOT_OS_REGEX = /(nuhk|curl|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask\ Jeeves\/Teoma|ia_archiver)/;
const REQUIRED_VERSION_PARTS = 3;
const userAgentRules = [
["aol", /AOLShield\/([0-9\._]+)/],
["brave", /Brave\/([0-9\._]+)/],
["edge", /Edge\/([0-9\._]+)/],
["edge-ios", /EdgiOS\/([0-9\._]+)/],
["yandexbrowser", /YaBrowser\/([0-9\._]+)/],
["kakaotalk", /KAKAOTALK\s([0-9\.]+)/],
["samsung", /SamsungBrowser\/([0-9\.]+)/],
["silk", /\bSilk\/([0-9._-]+)\b/],
["miui", /MiuiBrowser\/([0-9\.]+)$/],
["beaker", /BeakerBrowser\/([0-9\.]+)/],
["edge-chromium", /EdgA?\/([0-9\.]+)/],
[
"chromium-webview",
/(?!Chrom.*OPR)wv\).*Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/
],
["chrome", /(?!Chrom.*OPR)Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/],
["phantomjs", /PhantomJS\/([0-9\.]+)(:?\s|$)/],
["crios", /CriOS\/([0-9\.]+)(:?\s|$)/],
["firefox", /Firefox\/([0-9\.]+)(?:\s|$)/],
["fxios", /FxiOS\/([0-9\.]+)/],
["opera-mini", /Opera Mini.*Version\/([0-9\.]+)/],
["opera", /Opera\/([0-9\.]+)(?:\s|$)/],
["opera", /OPR\/([0-9\.]+)(:?\s|$)/],
["pie", /^Microsoft Pocket Internet Explorer\/(\d+\.\d+)$/],
["pie", /^Mozilla\/\d\.\d+\s\(compatible;\s(?:MSP?IE|MSInternet Explorer) (\d+\.\d+);.*Windows CE.*\)$/],
["netfront", /^Mozilla\/\d\.\d+.*NetFront\/(\d.\d)/],
["ie", /Trident\/7\.0.*rv\:([0-9\.]+).*\).*Gecko$/],
["ie", /MSIE\s([0-9\.]+);.*Trident\/[4-7].0/],
["ie", /MSIE\s(7\.0)/],
["bb10", /BB10;\sTouch.*Version\/([0-9\.]+)/],
["android", /Android\s([0-9\.]+)/],
["ios", /Version\/([0-9\._]+).*Mobile.*Safari.*/],
["safari", /Version\/([0-9\._]+).*Safari/],
["facebook", /FB[AS]V\/([0-9\.]+)/],
["instagram", /Instagram\s([0-9\.]+)/],
["ios-webview", /AppleWebKit\/([0-9\.]+).*Mobile/],
["ios-webview", /AppleWebKit\/([0-9\.]+).*Gecko\)$/],
["curl", /^curl\/([0-9\.]+)$/],
["searchbot", SEARCHBOX_UA_REGEX]
];
const operatingSystemRules = [
["iOS", /iP(hone|od|ad)/],
["Android OS", /Android/],
["BlackBerry OS", /BlackBerry|BB10/],
["Windows Mobile", /IEMobile/],
["Amazon OS", /Kindle/],
["Windows 3.11", /Win16/],
["Windows 95", /(Windows 95)|(Win95)|(Windows_95)/],
["Windows 98", /(Windows 98)|(Win98)/],
["Windows 2000", /(Windows NT 5.0)|(Windows 2000)/],
["Windows XP", /(Windows NT 5.1)|(Windows XP)/],
["Windows Server 2003", /(Windows NT 5.2)/],
["Windows Vista", /(Windows NT 6.0)/],
["Windows 7", /(Windows NT 6.1)/],
["Windows 8", /(Windows NT 6.2)/],
["Windows 8.1", /(Windows NT 6.3)/],
["Windows 10", /(Windows NT 10.0)/],
["Windows ME", /Windows ME/],
["Windows CE", /Windows CE|WinCE|Microsoft Pocket Internet Explorer/],
["Open BSD", /OpenBSD/],
["Sun OS", /SunOS/],
["Chrome OS", /CrOS/],
["Linux", /(Linux)|(X11)/],
["Mac OS", /(Mac_PowerPC)|(Macintosh)/],
["QNX", /QNX/],
["BeOS", /BeOS/],
["OS/2", /OS\/2/]
];
export function detect(userAgent) {
if (userAgent)
return parseUserAgent(userAgent);
if (typeof document === "undefined" && typeof navigator !== "undefined" && navigator.product === "ReactNative")
return new ReactNativeInfo();
if (typeof navigator !== "undefined")
return parseUserAgent(navigator.userAgent);
return getNodeVersion();
}
function matchUserAgent(ua) {
return ua !== "" && userAgentRules.reduce(
(matched, [browser, regex]) => {
if (matched)
return matched;
const uaMatch = regex.exec(ua);
return !!uaMatch && [browser, uaMatch];
},
false
);
}
export function browserName(ua) {
const data = matchUserAgent(ua);
return data ? data[0] : null;
}
export function parseUserAgent(ua) {
const matchedRule = matchUserAgent(ua);
if (!matchedRule)
return null;
const [name, match] = matchedRule;
if (name === "searchbot")
return new BotInfo();
let versionParts = match[1] && match[1].split(".").join("_").split("_").slice(0, 3);
if (versionParts) {
if (versionParts.length < REQUIRED_VERSION_PARTS) {
versionParts = [
...versionParts,
...createVersionParts(REQUIRED_VERSION_PARTS - versionParts.length)
];
}
} else {
versionParts = [];
}
const version = versionParts.join(".");
const os = detectOS(ua);
const searchBotMatch = SEARCHBOT_OS_REGEX.exec(ua);
if (searchBotMatch && searchBotMatch[1])
return new SearchBotDeviceInfo(name, version, os, searchBotMatch[1]);
return new BrowserInfo(name, version, os);
}
export function detectOS(ua) {
for (let ii = 0, count = operatingSystemRules.length; ii < count; ii++) {
const [os, regex] = operatingSystemRules[ii];
const match = regex.exec(ua);
if (match)
return os;
}
return null;
}
export function getNodeVersion() {
const isNode = typeof process !== "undefined" && process.version;
return isNode ? new NodeInfo(process.version.slice(1)) : null;
}
function createVersionParts(count) {
const output = [];
for (let ii = 0; ii < count; ii++)
output.push("0");
return output;
}