Rearrange internal class & remove old Safari map

This commit is contained in:
Faisal Salman 2023-04-08 04:40:59 +07:00
parent 59d8d836c2
commit e01663b48f
2 changed files with 189 additions and 174 deletions

View File

@ -95,18 +95,7 @@
// Helper // Helper
////////// //////////
var assignFromEntries = function (arr) { var extend = function (regexes, extensions) {
for (var i in arr) {
var propName = arr[i];
if (typeof propName == OBJ_TYPE && propName.length == 2) {
this[propName[0]] = propName[1];
} else {
this[propName] = undefined;
}
}
return this;
},
extend = function (regexes, extensions) {
var mergedRegexes = {}; var mergedRegexes = {};
for (var i in regexes) { for (var i in regexes) {
mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i]; mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
@ -150,6 +139,17 @@
majorize = function (version) { majorize = function (version) {
return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined; return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
}, },
setProps = function (arr) {
for (var i in arr) {
var propName = arr[i];
if (typeof propName == OBJ_TYPE && propName.length == 2) {
this[propName[0]] = propName[1];
} else {
this[propName] = undefined;
}
}
return this;
},
strip = function (pattern, str) { strip = function (pattern, str) {
return str.replace(pattern, EMPTY); return str.replace(pattern, EMPTY);
}, },
@ -243,18 +243,7 @@
// String map // String map
////////////// //////////////
// Safari < 3.0 var windowsVersionMap = {
var oldSafariMap = {
'1.0' : '/8',
'1.2' : '/1',
'1.3' : '/3',
'2.0' : '/412',
'2.0.2' : '/416',
'2.0.3' : '/417',
'2.0.4' : '/419',
'?' : '/'
},
windowsVersionMap = {
'ME' : '4.90', 'ME' : '4.90',
'NT 3.11' : 'NT3.51', 'NT 3.11' : 'NT3.51',
'NT 4.0' : 'NT4.0', 'NT 4.0' : 'NT4.0',
@ -386,7 +375,7 @@
/version\/([\w\.\,]+) .*(safari)/i // Safari /version\/([\w\.\,]+) .*(safari)/i // Safari
], [VERSION, NAME], [ ], [VERSION, NAME], [
/webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
], [NAME, [VERSION, strMapper, oldSafariMap]], [ ], [NAME, [VERSION, '1']], [
/(webkit|khtml)\/([\w\.]+)/i /(webkit|khtml)\/([\w\.]+)/i
], [NAME, VERSION], [ ], [NAME, VERSION], [
@ -427,7 +416,7 @@
/((?:i[346]|x)86)[;\)]/i // IA32 (x86) /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
], [[ARCHITECTURE, 'ia32']], [ ], [[ARCHITECTURE, 'ia32']], [
/\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64 /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64
], [[ARCHITECTURE, 'arm64']], [ ], [[ARCHITECTURE, 'arm64']], [
/\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF
@ -811,23 +800,23 @@
var defaultProps = (function () { var defaultProps = (function () {
var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}}; var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
assignFromEntries.call(props.init, [ setProps.call(props.init, [
[UA_BROWSER, [NAME, VERSION, MAJOR]], [UA_BROWSER, [NAME, VERSION, MAJOR]],
[UA_CPU, [ARCHITECTURE]], [UA_CPU, [ARCHITECTURE]],
[UA_DEVICE, [TYPE, MODEL, VENDOR]], [UA_DEVICE, [TYPE, MODEL, VENDOR]],
[UA_ENGINE, [NAME, VERSION]], [UA_ENGINE, [NAME, VERSION]],
[UA_OS, [NAME, VERSION]] [UA_OS, [NAME, VERSION]]
]); ]);
assignFromEntries.call(props.isIgnore, [ setProps.call(props.isIgnore, [
[UA_BROWSER, [VERSION, MAJOR]], [UA_BROWSER, [VERSION, MAJOR]],
[UA_ENGINE, [VERSION]], [UA_ENGINE, [VERSION]],
[UA_OS, [VERSION]] [UA_OS, [VERSION]]
]); ]);
assignFromEntries.call(props.isIgnoreRgx, [ setProps.call(props.isIgnoreRgx, [
[UA_BROWSER, / ?browser$/i], [UA_BROWSER, / ?browser$/i],
[UA_OS, / ?os$/i] [UA_OS, / ?os$/i]
]); ]);
assignFromEntries.call(props.toString, [ setProps.call(props.toString, [
[UA_BROWSER, [NAME, VERSION]], [UA_BROWSER, [NAME, VERSION]],
[UA_CPU, [ARCHITECTURE]], [UA_CPU, [ARCHITECTURE]],
[UA_DEVICE, [VENDOR, MODEL]], [UA_DEVICE, [VENDOR, MODEL]],
@ -837,7 +826,7 @@
return props; return props;
})(); })();
var createUAParserData = function (itemType, ua, rgxMap, uaCH) { var createUAParserData = function (item, itemType) {
var init_props = defaultProps.init[itemType], var init_props = defaultProps.init[itemType],
is_ignoreProps = defaultProps.isIgnore[itemType] || 0, is_ignoreProps = defaultProps.isIgnore[itemType] || 0,
@ -845,27 +834,30 @@
toString_props = defaultProps.toString[itemType] || 0; toString_props = defaultProps.toString[itemType] || 0;
function UAParserData () { function UAParserData () {
assignFromEntries.call(this, init_props); setProps.call(this, init_props);
} }
UAParserData.prototype.withClientHints = function () {
var prevData = this; UAParserData.prototype.getItem = function () {
return item;
};
UAParserData.prototype.withClientHints = function () {
// nodejs / non-client-hints browsers // nodejs / non-client-hints browsers
if (!NAVIGATOR_UADATA) { if (!NAVIGATOR_UADATA) {
var item = new UAParserItem(itemType, ua, rgxMap, uaCH); return item
item.data = prevData; .parseCH()
return item.parseCH().get(); .get();
} }
// browsers based on chromium 85+ // browsers based on chromium 85+
return NAVIGATOR_UADATA return NAVIGATOR_UADATA
.getHighEntropyValues(CH_ALL_VALUES) .getHighEntropyValues(CH_ALL_VALUES)
.then(function (res) { .then(function (res) {
var JS_UACH = new UAParserDataCH(res, false); return item
var item = new UAParserItem(itemType, ua, rgxMap, JS_UACH); .setCH(new UAParserDataCH(res, false))
item.data = prevData; .parseCH()
return item.parseCH().get(); .get();
}); });
}; };
@ -923,9 +915,9 @@
function UAParserDataCH (uach, isHTTP_UACH) { function UAParserDataCH (uach, isHTTP_UACH) {
uach = uach || {}; uach = uach || {};
assignFromEntries.call(this, CH_ALL_VALUES); setProps.call(this, CH_ALL_VALUES);
if (isHTTP_UACH) { if (isHTTP_UACH) {
assignFromEntries.call(this, [ setProps.call(this, [
[BRANDS, itemListToArray(uach[CH_HEADER])], [BRANDS, itemListToArray(uach[CH_HEADER])],
[FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])], [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
[BRANDS, itemListToArray(uach[CH_HEADER])], [BRANDS, itemListToArray(uach[CH_HEADER])],
@ -941,133 +933,138 @@
if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop]; if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
} }
} }
return this;
} }
function UAParserItem (itemType, ua, rgxMap, uaCH) { function UAParserItem (itemType, ua, rgxMap, uaCH) {
assignFromEntries.call(this, [
this.get = function (prop) {
if (!prop) return this.data;
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
};
this.set = function (prop, val) {
this.data[prop] = val;
return this;
};
this.setCH = function (ch) {
this.uaCH = ch;
return this;
};
this.detectFeature = function () {
if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
switch (this.itemType) {
case UA_BROWSER:
// Brave-specific detection
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
this.set(NAME, 'Brave');
}
break;
case UA_DEVICE:
// Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
this.set(TYPE, MOBILE);
}
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
this.set(MODEL, 'iPad')
.set(TYPE, TABLET);
}
break;
case UA_OS:
// Chrome-specific detection: check for 'platform' value of navigator.userAgentData
if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
}
}
}
return this;
};
this.parseUA = function () {
if (this.itemType != UA_RESULT) {
rgxMapper.call(this.data, this.ua, this.rgxMap);
}
if (this.itemType == UA_BROWSER) {
this.set(MAJOR, majorize(this.get(VERSION)));
}
return this;
};
this.parseCH = function () {
var ua = this.ua,
uaCH = this.uaCH,
rgxMap = this.rgxMap;
switch (this.itemType) {
case UA_BROWSER:
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
if (brands) {
for (var i in brands) {
var brandName = brands[i].brand,
brandVersion = brands[i].version;
if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
this.set(NAME, strip(GOOGLE+' ', brandName))
.set(VERSION, brandVersion)
.set(MAJOR, majorize(brandVersion));
}
}
}
break;
case UA_CPU:
var archName = uaCH[ARCHITECTURE];
if (archName) {
if (archName && uaCH[BITNESS] == '64') archName += '64';
rgxMapper.call(this.data, archName + ';', rgxMap);
}
break;
case UA_DEVICE:
if (uaCH[MOBILE]) {
this.set(TYPE, MOBILE);
}
if (uaCH[MODEL]) {
this.set(MODEL, uaCH[MODEL]);
}
break;
case UA_OS:
var osName = uaCH[PLATFORM];
if(osName) {
var osVersion = uaCH[PLATFORMVER];
if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
this.set(NAME, osName)
.set(VERSION, osVersion);
}
break;
case UA_RESULT:
var data = this.data;
var parse = function (itemType) {
return data[itemType]
.getItem()
.setCH(uaCH)
.parseCH()
.get();
};
this.set('ua', ua)
.set(UA_BROWSER, parse(UA_BROWSER))
.set(UA_CPU, parse(UA_CPU))
.set(UA_DEVICE, parse(UA_DEVICE))
.set(UA_ENGINE, parse(UA_ENGINE))
.set(UA_OS, parse(UA_OS));
}
return this;
};
setProps.call(this, [
['itemType', itemType], ['itemType', itemType],
['ua', ua], ['ua', ua],
['uaCH', uaCH], ['uaCH', uaCH],
['rgxMap', rgxMap], ['rgxMap', rgxMap],
['data', createUAParserData(itemType, ua, rgxMap, uaCH)] ['data', createUAParserData(this, itemType)]
]); ]);
if(this.itemType == UA_RESULT) {
var createUAParserItem = function (itemType) {
return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseUA().get();
};
this.set('ua', ua)
.set(UA_BROWSER, createUAParserItem(UA_BROWSER))
.set(UA_CPU, createUAParserItem(UA_CPU))
.set(UA_DEVICE, createUAParserItem(UA_DEVICE))
.set(UA_ENGINE, createUAParserItem(UA_ENGINE))
.set(UA_OS, createUAParserItem(UA_OS))
.get();
}
return this; return this;
} }
UAParserItem.prototype.detectFeature = function () {
var isSelfNav = NAVIGATOR && NAVIGATOR.userAgent == this.ua;
switch(this.itemType) {
case UA_BROWSER:
// Brave-specific detection
if (isSelfNav && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
this.set(NAME, 'Brave');
}
this.set(MAJOR, majorize(this.get(VERSION)));
break;
case UA_DEVICE:
if (isSelfNav && !this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
this.set(TYPE, MOBILE);
}
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
if (isSelfNav && this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
this.set(MODEL, 'iPad')
.set(TYPE, TABLET);
}
break;
case UA_OS:
if (isSelfNav && !this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
}
}
return this;
};
UAParserItem.prototype.get = function (prop) {
if (!prop) return this.data;
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
};
UAParserItem.prototype.parseUA = function () {
if (this.itemType != UA_RESULT) {
rgxMapper.call(this.data, this.ua, this.rgxMap);
}
this.detectFeature();
return this;
};
UAParserItem.prototype.parseCH = function () {
var ua = this.ua,
uaCH = this.uaCH,
rgxMap = this.rgxMap;
switch (this.itemType) {
case UA_BROWSER:
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
if (brands) {
for (var i in brands) {
var brandName = brands[i].brand,
brandVersion = brands[i].version;
if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
this.set(NAME, strip(GOOGLE+' ', brandName))
.set(VERSION, brandVersion)
.set(MAJOR, majorize(brandVersion));
}
}
}
break;
case UA_CPU:
var archName = uaCH[ARCHITECTURE];
if (archName) {
if (archName && uaCH[BITNESS] == '64') archName += '64';
rgxMapper.call(this.data, archName + ';', rgxMap);
}
break;
case UA_DEVICE:
if (uaCH[MOBILE]) {
this.set(TYPE, MOBILE);
}
if (uaCH[MODEL]) {
this.set(MODEL, uaCH[MODEL]);
}
break;
case UA_OS:
var osName = uaCH[PLATFORM];
if(osName) {
var osVersion = uaCH[PLATFORMVER];
if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
this.set(NAME, osName)
.set(VERSION, osVersion);
}
break;
case UA_RESULT:
var prevData = this.data;
var createUAParserItemWithCH = function (itemType) {
var item = new UAParserItem(itemType, ua, rgxMap[itemType], uaCH);
item.data = prevData[itemType];
return item.parseCH().get();
};
this.set('ua', ua)
.set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER))
.set(UA_CPU, createUAParserItemWithCH(UA_CPU))
.set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE))
.set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE))
.set(UA_OS, createUAParserItemWithCH(UA_OS));
}
return this;
};
UAParserItem.prototype.set = function (prop, val) {
this.data[prop] = val;
return this;
};
function UAParser (ua, extensions, headers) { function UAParser (ua, extensions, headers) {
@ -1104,26 +1101,44 @@
extend(defaultRegexes, extensions) : extend(defaultRegexes, extensions) :
defaultRegexes, defaultRegexes,
createUAParserItemFunc = function (itemType) { createItemFunc = function (itemType) {
return function () { if (itemType == UA_RESULT) {
return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).parseUA().get(); return function () {
}; return new UAParserItem(itemType, userAgent, regexMap, HTTP_UACH)
.set('ua', userAgent)
.set(UA_BROWSER, this.getBrowser())
.set(UA_CPU, this.getCPU())
.set(UA_DEVICE, this.getDevice())
.set(UA_ENGINE, this.getEngine())
.set(UA_OS, this.getOS())
.get();
};
} else {
return function () {
return new UAParserItem(itemType, userAgent, regexMap[itemType], HTTP_UACH)
.parseUA()
.detectFeature()
.get();
};
}
}; };
// public methods // public methods
assignFromEntries.call(this, [ setProps.call(this, [
['getBrowser', createUAParserItemFunc(UA_BROWSER)], ['getBrowser', createItemFunc(UA_BROWSER)],
['getCPU', createUAParserItemFunc(UA_CPU)], ['getCPU', createItemFunc(UA_CPU)],
['getDevice', createUAParserItemFunc(UA_DEVICE)], ['getDevice', createItemFunc(UA_DEVICE)],
['getEngine', createUAParserItemFunc(UA_ENGINE)], ['getEngine', createItemFunc(UA_ENGINE)],
['getOS', createUAParserItemFunc(UA_OS)], ['getOS', createItemFunc(UA_OS)],
['getResult', createUAParserItemFunc(UA_RESULT)], ['getResult', createItemFunc(UA_RESULT)],
['getUA', function () { return userAgent; }], ['getUA', function () { return userAgent; }],
['setUA', function (ua) { ['setUA', function (ua) {
userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua; userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
return this; return this;
}] }]
]).setUA(userAgent); ])
.setUA(userAgent);
return this; return this;
} }

View File

@ -1084,8 +1084,8 @@
"expect" : "expect" :
{ {
"name" : "Safari", "name" : "Safari",
"version" : "2.0.4", "version" : "1",
"major" : "2" "major" : "1"
} }
}, },
{ {