Skip to content

Instantly share code, notes, and snippets.

@maxpatiiuk
Last active May 20, 2022 20:23
Show Gist options
  • Select an option

  • Save maxpatiiuk/9c8bda22052f33e9f94e6d189bda0def to your computer and use it in GitHub Desktop.

Select an option

Save maxpatiiuk/9c8bda22052f33e9f94e6d189bda0def to your computer and use it in GitHub Desktop.
Simple parser for user agent strings
// Using TypeScript here, but GitHub Gist does not have syntax highlighting for TypeScript
const f = {
maybe: <VALUE, RETURN>(
value: VALUE | undefined,
callback: (value: VALUE) => RETURN
): RETURN | undefined =>
typeof value === 'undefined' ? undefined : callback(value),
};
export function mappedFind<ITEM, RETURN_TYPE>(
array: RA<ITEM>,
callback: (item: ITEM, index: number) => RETURN_TYPE | undefined
): RETURN_TYPE | undefined {
let value = undefined;
array.some((item, index) => {
value = callback(item, index);
return typeof value !== 'undefined';
});
return value;
}
/**
* Parse User Agent string into human friendly labels.
* Not meant for programmatic usage, only for presentational usage
*/
export const parseUserAgent = (
userAgentString: string
): { readonly os: string; readonly browser: string } => ({
os:
mappedFind(Object.entries(osSimpleNeedles), ([needle, label]) =>
userAgentString.includes(needle) ? label : undefined
) ??
mappedFind(Object.entries(osComplexNeedles), ([needle, regex]) =>
userAgentString.includes(needle)
? userAgentString.match(regex)?.[1]
: undefined
) ??
userAgentString,
browser:
mappedFind(Object.entries(browserSimpleNeedles), ([needle, label]) =>
userAgentString.includes(needle) ? label : undefined
) ??
mappedFind(
Object.entries(browserComplexNeedles),
([needle, [regex, replacement]]) =>
userAgentString.includes(needle)
? f.maybe(userAgentString.match(regex)?.[0], (substring) =>
substring.replace(regex, replacement)
)
: undefined
) ??
userAgentString,
});
const osSimpleNeedles = {
'Windows NT 10.0': 'Windows 10',
'Windows NT 6.3': 'Windows 8.1',
'Windows NT 6.2': 'Windows 7',
'Windows NT 6.0': 'Windows Vista',
'Windows NT 5.1': 'Windows XP',
'Mac OS X 10_15': 'Mac OS X Catalina',
'Mac OS X 10_14': 'Mac OS X Mojave',
'Mac OS X 10_13': 'Mac OS X High Sierra',
'Mac OS X 10_12': 'Mac OS X Sierra',
'Mac OS X 10_11': 'Mac OS X El Capitan',
'Mac OS X 10_10': 'Mac OS X Yosemite',
'Mac OS X 10_9': 'Mac OS X Mavericks',
'Mac OS X 10_8': 'Mac OS X Mountain Lion',
CrOS: 'Chrome OS',
'Ubuntu; Linux x86_64': 'Ubuntu x64',
'Linux x86_64': 'Linux x64',
} as const;
const osComplexNeedles = {
Android: /Android \d/,
'iPhone OS': /iPhone OS \d+/,
'Mac OS X': /Mac OS X [\d_]+/,
} as const;
const browserSimpleNeedles = {
'Trident/7.0': 'Internet Explorer 11',
} as const;
const browserComplexNeedles = {
Version: [/Version\/(\d+)/, 'Safari $1'],
Firefox: [/Firefox\/(\d+)/, 'Firefox $1'],
MSIE: [/MSIE d+.0/, 'Internet Explorer $1'],
SamsungBrowser: [/SamsungBrowser\/(\d+)/, 'Samsung Browser $1'],
Edg: [/Edge?\/(\d+)/, 'Microsoft Edge $1'],
Chrom: [/Chrome\/(\d+) Mobile/, 'Chrome Mobile $1'],
Chrome: [/Chrome\/(\d+)/, 'Chrome $1'],
} as const;
// Example usage:
console.table(
parseUserAgent(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment