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], [
@ -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,70 +933,66 @@
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, [
['itemType', itemType], this.get = function (prop) {
['ua', ua], if (!prop) return this.data;
['uaCH', uaCH], return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
['rgxMap', rgxMap],
['data', createUAParserData(itemType, ua, rgxMap, uaCH)]
]);
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)) this.set = function (prop, val) {
.set(UA_CPU, createUAParserItem(UA_CPU)) this.data[prop] = val;
.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; this.setCH = function (ch) {
this.uaCH = ch;
return this;
};
this.detectFeature = function () {
if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
switch (this.itemType) { switch (this.itemType) {
case UA_BROWSER: case UA_BROWSER:
// Brave-specific detection // Brave-specific detection
if (isSelfNav && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) { if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
this.set(NAME, 'Brave'); this.set(NAME, 'Brave');
} }
this.set(MAJOR, majorize(this.get(VERSION)));
break; break;
case UA_DEVICE: case UA_DEVICE:
if (isSelfNav && !this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) { // Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
this.set(TYPE, MOBILE); this.set(TYPE, MOBILE);
} }
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties // 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) { if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
this.set(MODEL, 'iPad') this.set(MODEL, 'iPad')
.set(TYPE, TABLET); .set(TYPE, TABLET);
} }
break; break;
case UA_OS: case UA_OS:
if (isSelfNav && !this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) { // 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]); this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
} }
} }
}
return this; return this;
}; };
UAParserItem.prototype.get = function (prop) {
if (!prop) return this.data; this.parseUA = function () {
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
};
UAParserItem.prototype.parseUA = function () {
if (this.itemType != UA_RESULT) { if (this.itemType != UA_RESULT) {
rgxMapper.call(this.data, this.ua, this.rgxMap); rgxMapper.call(this.data, this.ua, this.rgxMap);
} }
this.detectFeature(); if (this.itemType == UA_BROWSER) {
this.set(MAJOR, majorize(this.get(VERSION)));
}
return this; return this;
}; };
UAParserItem.prototype.parseCH = function () {
this.parseCH = function () {
var ua = this.ua, var ua = this.ua,
uaCH = this.uaCH, uaCH = this.uaCH,
rgxMap = this.rgxMap; rgxMap = this.rgxMap;
@ -1049,25 +1037,34 @@
} }
break; break;
case UA_RESULT: case UA_RESULT:
var prevData = this.data; var data = this.data;
var createUAParserItemWithCH = function (itemType) { var parse = function (itemType) {
var item = new UAParserItem(itemType, ua, rgxMap[itemType], uaCH); return data[itemType]
item.data = prevData[itemType]; .getItem()
return item.parseCH().get(); .setCH(uaCH)
.parseCH()
.get();
}; };
this.set('ua', ua) this.set('ua', ua)
.set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER)) .set(UA_BROWSER, parse(UA_BROWSER))
.set(UA_CPU, createUAParserItemWithCH(UA_CPU)) .set(UA_CPU, parse(UA_CPU))
.set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE)) .set(UA_DEVICE, parse(UA_DEVICE))
.set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE)) .set(UA_ENGINE, parse(UA_ENGINE))
.set(UA_OS, createUAParserItemWithCH(UA_OS)); .set(UA_OS, parse(UA_OS));
} }
return this; return this;
}; };
UAParserItem.prototype.set = function (prop, val) {
this.data[prop] = val; setProps.call(this, [
['itemType', itemType],
['ua', ua],
['uaCH', uaCH],
['rgxMap', rgxMap],
['data', createUAParserData(this, itemType)]
]);
return this; 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) {
if (itemType == UA_RESULT) {
return function () { return function () {
return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).parseUA().get(); 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"
} }
}, },
{ {