From 15226914260142b0ef96b081565d5f30198ed521 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 26 Aug 2023 04:55:07 +0700 Subject: [PATCH] [ua-client-hints] Refactor `UAClientHints` --- package-lock.json | 10 +- package.json | 2 +- script/build-module.js | 6 +- .../client-hints-helpers.d.ts | 35 ----- .../client-hints-helpers.js | 88 ------------ .../client-hints-helpers.mjs | 92 ------------ src/client-hints-helpers/readme.md | 75 ---------- .../package.json | 10 +- src/ua-client-hints/readme.md | 128 +++++++++++++++++ src/ua-client-hints/ua-client-hints.d.ts | 39 +++++ src/ua-client-hints/ua-client-hints.js | 130 +++++++++++++++++ src/ua-client-hints/ua-client-hints.mjs | 134 ++++++++++++++++++ test/mocha-test-helpers.js | 28 ++-- 13 files changed, 466 insertions(+), 311 deletions(-) delete mode 100644 src/client-hints-helpers/client-hints-helpers.d.ts delete mode 100644 src/client-hints-helpers/client-hints-helpers.js delete mode 100644 src/client-hints-helpers/client-hints-helpers.mjs delete mode 100644 src/client-hints-helpers/readme.md rename src/{client-hints-helpers => ua-client-hints}/package.json (78%) create mode 100644 src/ua-client-hints/readme.md create mode 100644 src/ua-client-hints/ua-client-hints.d.ts create mode 100644 src/ua-client-hints/ua-client-hints.js create mode 100644 src/ua-client-hints/ua-client-hints.mjs diff --git a/package-lock.json b/package-lock.json index 92bbfbd..f2262f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ ], "license": "MIT", "workspaces": [ - "src/client-hints-helpers", + "src/ua-client-hints", "src/user-agent-helpers" ], "devDependencies": { @@ -768,6 +768,10 @@ "resolved": "src/client-hints-helpers", "link": true }, + "node_modules/@ua-parser-js/ua-client-hints": { + "resolved": "src/ua-client-hints", + "link": true + }, "node_modules/@ua-parser-js/user-agent-helpers": { "resolved": "src/user-agent-helpers", "link": true @@ -3794,6 +3798,10 @@ "extraneous": true, "license": "MIT" }, + "src/ua-client-hints": { + "version": "0.0.1", + "license": "MIT" + }, "src/user-agent-helpers": { "name": "@ua-parser-js/user-agent-helpers", "version": "0.0.1", diff --git a/package.json b/package.json index f687f88..e4b6207 100644 --- a/package.json +++ b/package.json @@ -219,7 +219,7 @@ } ], "workspaces": [ - "src/client-hints-helpers", + "src/ua-client-hints", "src/user-agent-helpers" ] } diff --git a/script/build-module.js b/script/build-module.js index 3b00317..d3c7935 100755 --- a/script/build-module.js +++ b/script/build-module.js @@ -54,9 +54,9 @@ const modules = [ replacements : [] }, { - src : 'src/client-hints-helpers/client-hints-helpers.js', - dest : 'src/client-hints-helpers/client-hints-helpers.mjs', - title : '@ua-parser-js/client-hints-helpers', + src : 'src/ua-client-hints/ua-client-hints.js', + dest : 'src/ua-client-hints/ua-client-hints.mjs', + title : '@ua-parser-js/ua-client-hints', replacements : [] } ]; diff --git a/src/client-hints-helpers/client-hints-helpers.d.ts b/src/client-hints-helpers/client-hints-helpers.d.ts deleted file mode 100644 index 00f98f8..0000000 --- a/src/client-hints-helpers/client-hints-helpers.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -interface IBrowser { - brand: string; - version: string; -} - -interface ClientHintsJSLowEntropy { - brands: Array; - mobile: boolean; - platform: string; -} - -export interface ClientHintsJSHighEntropy extends ClientHintsJSLowEntropy { - architecture?: string; - bitness?: string; - formFactor?: string; - fullVersionList?: Array; - model?: string; - platformVersion?: string; - wow64?: boolean; -}; - -export interface ClientHintsHTTPHeaders { - 'sec-ch-ua-arch'?: string; - 'sec-ch-ua-bitness'?: string; - 'sec-ch-ua'?: string; - 'sec-ch-ua-form-factor'?: string; - 'sec-ch-ua-full-version-list'?: string; - 'sec-ch-ua-mobile'?: string; - 'sec-ch-ua-model'?: string; - 'sec-ch-ua-platform'?: string; - 'sec-ch-ua-platform-version'?: string; - 'sec-ch-ua-wow64'?: string; -} - -export function UACHParser(headers: ClientHintsHTTPHeaders): ClientHintsJSHighEntropy; \ No newline at end of file diff --git a/src/client-hints-helpers/client-hints-helpers.js b/src/client-hints-helpers/client-hints-helpers.js deleted file mode 100644 index 5fa3bbc..0000000 --- a/src/client-hints-helpers/client-hints-helpers.js +++ /dev/null @@ -1,88 +0,0 @@ -//////////////////////////////////////////////////// -/* A collection of utility methods for client-hints - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -/////////////////////////////////////////////////// - -/*jshint esversion: 11 */ - -const UACHMap = { - 'sec-ch-ua-arch' : { - prop : 'architecture', - type : 'sf-string' - }, - 'sec-ch-ua-bitness' : { - prop : 'bitness', - type : 'sf-string' - }, - 'sec-ch-ua' : { - prop : 'brands', - type : 'sf-list' - }, - 'sec-ch-ua-form-factor' : { - prop : 'formFactor', - type : 'sf-string' - }, - 'sec-ch-ua-full-version-list' : { - prop : 'fullVersionList', - type : 'sf-list' - }, - 'sec-ch-ua-mobile' : { - prop : 'mobile', - type : 'sf-boolean', - }, - 'sec-ch-ua-model' : { - prop : 'model', - type : 'sf-string', - }, - 'sec-ch-ua-platform' : { - prop : 'platform', - type : 'sf-string' - }, - 'sec-ch-ua-platform-version' : { - prop : 'platformVersion', - type : 'sf-string' - }, - 'sec-ch-ua-wow64' : { - prop : 'wow64', - type : 'sf-boolean' - } -}; - -const UACHParser = (headers) => { - const parse = (str, type) => { - if (!str) { - return ''; - } - switch (type) { - case 'sf-boolean': - return /\?1/.test(str); - case 'sf-list': - return str.replace(/\\?\"/g, '') - .split(', ') - .map(brands => { - const [brand, version] = brands.split(';v='); - return { - brand : brand, - version : version - }; - }); - case 'sf-string': - default: - return str.replace(/\\?\"/g, ''); - } - }; - let ch = {}; - Object.keys(UACHMap).forEach(field => { - if (headers.hasOwnProperty(field)) { - const { prop, type } = UACHMap[field]; - ch[prop] = parse(headers[field], type); - } - }); - return ch; -}; - -module.exports = { - UACHParser -}; \ No newline at end of file diff --git a/src/client-hints-helpers/client-hints-helpers.mjs b/src/client-hints-helpers/client-hints-helpers.mjs deleted file mode 100644 index 184e000..0000000 --- a/src/client-hints-helpers/client-hints-helpers.mjs +++ /dev/null @@ -1,92 +0,0 @@ -// Generated ESM version of @ua-parser-js/client-hints-helpers -// DO NOT EDIT THIS FILE! -// Source: /src/client-hints-helpers/client-hints-helpers.js - -//////////////////////////////////////////////////// -/* A collection of utility methods for client-hints - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -/////////////////////////////////////////////////// - -/*jshint esversion: 11 */ - -const UACHMap = { - 'sec-ch-ua-arch' : { - prop : 'architecture', - type : 'sf-string' - }, - 'sec-ch-ua-bitness' : { - prop : 'bitness', - type : 'sf-string' - }, - 'sec-ch-ua' : { - prop : 'brands', - type : 'sf-list' - }, - 'sec-ch-ua-form-factor' : { - prop : 'formFactor', - type : 'sf-string' - }, - 'sec-ch-ua-full-version-list' : { - prop : 'fullVersionList', - type : 'sf-list' - }, - 'sec-ch-ua-mobile' : { - prop : 'mobile', - type : 'sf-boolean', - }, - 'sec-ch-ua-model' : { - prop : 'model', - type : 'sf-string', - }, - 'sec-ch-ua-platform' : { - prop : 'platform', - type : 'sf-string' - }, - 'sec-ch-ua-platform-version' : { - prop : 'platformVersion', - type : 'sf-string' - }, - 'sec-ch-ua-wow64' : { - prop : 'wow64', - type : 'sf-boolean' - } -}; - -const UACHParser = (headers) => { - const parse = (str, type) => { - if (!str) { - return ''; - } - switch (type) { - case 'sf-boolean': - return /\?1/.test(str); - case 'sf-list': - return str.replace(/\\?\"/g, '') - .split(', ') - .map(brands => { - const [brand, version] = brands.split(';v='); - return { - brand : brand, - version : version - }; - }); - case 'sf-string': - default: - return str.replace(/\\?\"/g, ''); - } - }; - let ch = {}; - Object.keys(UACHMap).forEach(field => { - if (headers.hasOwnProperty(field)) { - const { prop, type } = UACHMap[field]; - ch[prop] = parse(headers[field], type); - } - }); - return ch; -}; - -export { - UACHParser -}; \ No newline at end of file diff --git a/src/client-hints-helpers/readme.md b/src/client-hints-helpers/readme.md deleted file mode 100644 index b1f569e..0000000 --- a/src/client-hints-helpers/readme.md +++ /dev/null @@ -1,75 +0,0 @@ -# @ua-parser-js/client-hints-helpers - -This is a [UAParser.js](https://github.com/faisalman/ua-parser-js) module that contains a collection of utility methods for working with user-agent client-hints. - -```sh -npm i @ua-parser-js/client-hints-helpers -``` - -### * `UACHParser(headers:object):object` - -Parse user-agent client-hints HTTP headers (sec-ch-ua) into its JS API equivalent - -## Code Example - -```js -import { UACHParser } from '@ua-parser-js/client-hints-helpers'; - -/* - Suppose we're in a server having this client hints data: - - const headers = { - 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', - 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', - 'sec-ch-ua-arch' : 'arm', - 'sec-ch-ua-bitness' : '64', - 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : 'Pixel 99', - 'sec-ch-ua-platform' : 'Linux', - 'sec-ch-ua-platform-version' : '13', - 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' - }; -*/ - -const userAgentData = UACHParser(headers); - -console.log(userAgentData); -/* - { - "architecture": "arm", - "bitness": "64", - "brands": [ - { - "brand": "Chromium", - "version": "93" - }, - { - "brand": "Google Chrome", - "version": "93" - }, - { - "brand": " Not;A Brand", - "version": "99" - } - ], - "fullVersionList": [ - { - "brand": "Chromium", - "version": "93.0.1.2" - }, - { - "brand": "Google Chrome", - "version": "93.0.1.2" - }, - { - "brand": " Not;A Brand", - "version": "99.0.1.2" - } - ], - "mobile": true, - "model": "Pixel 99", - "platform": "Linux", - "platformVersion": "13" - } -*/ -``` \ No newline at end of file diff --git a/src/client-hints-helpers/package.json b/src/ua-client-hints/package.json similarity index 78% rename from src/client-hints-helpers/package.json rename to src/ua-client-hints/package.json index 39a2dc2..0ea28cd 100644 --- a/src/client-hints-helpers/package.json +++ b/src/ua-client-hints/package.json @@ -1,11 +1,11 @@ { - "title": "Client-Hints Helpers", - "name": "@ua-parser-js/client-hints-helpers", + "title": "User-Agent Client Hints", + "name": "@ua-parser-js/ua-client-hints", "version": "0.0.1", "author": "Faisal Salman ", - "description": "A collection of utility methods for working with client-hints", - "main": "client-hints-helpers.js", - "module": "client-hints-helpers.mjs", + "description": "A collection of utility methods for working with user-agent client hints", + "main": "ua-client-hints.js", + "module": "ua-client-hints.mjs", "scripts": { "test": "mocha ../../test/mocha-test-helpers" }, diff --git a/src/ua-client-hints/readme.md b/src/ua-client-hints/readme.md new file mode 100644 index 0000000..253f4eb --- /dev/null +++ b/src/ua-client-hints/readme.md @@ -0,0 +1,128 @@ +# @ua-parser-js/ua-client-hints + +This is a [UAParser.js](https://github.com/faisalman/ua-parser-js) module that contains a collection of utility methods for working with user-agent client hints. + +```sh +npm i @ua-parser-js/ua-client-hints +``` + +### * `getUAData([props:array]):object` + +Get user-agent client hints values of current instance in form of JS object representation + +### * `setUAData([uaData:object]):UAClientHints` + +Set values of user-agent client hints for the current instance either from navigator.userAgentData or from HTTP headers (Sec-CH-UA-*) + +### * `getSerializedUAData([props:array]):object` + +Get user-agent client hints values of current instance in form of HTTP headers string representation (Sec-CH-UA-*) + +## Code Example + +```js +import { UAClientHints } from '@ua-parser-js/ua-client-hints'; + +/* + Suppose we're in a server having this client hints data: + + const httpHeaders = { + 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', + 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', + 'sec-ch-ua-arch' : 'arm', + 'sec-ch-ua-bitness' : '64', + 'sec-ch-ua-mobile' : '?1', + 'sec-ch-ua-model' : 'Pixel 99', + 'sec-ch-ua-platform' : 'Linux', + 'sec-ch-ua-platform-version' : '13' + }; +*/ + +const uaCH = new UAClientHints(); +uaCH.setUAData(httpHeaders); +const uaCHData1 = uaCH.getUAData(); +const uaCHData2 = uaCH.getUAData(['architecture', 'bitness']); + +console.log(uaCHData1); +/* + { + "architecture": "arm", + "bitness": "64", + "brands": [ + { + "brand": "Chromium", + "version": "93" + }, + { + "brand": "Google Chrome", + "version": "93" + }, + { + "brand": " Not;A Brand", + "version": "99" + } + ], + "fullVersionList": [ + { + "brand": "Chromium", + "version": "93.0.1.2" + }, + { + "brand": "Google Chrome", + "version": "93.0.1.2" + }, + { + "brand": " Not;A Brand", + "version": "99.0.1.2" + } + ], + "mobile": true, + "model": "Pixel 99", + "platform": "Linux", + "platformVersion": "13", + "wow64": null, + "formFactor": null + } +*/ + +console.log(uaCHData2); +/* + { + "architecture": "arm", + "bitness": "64" + } +*/ + +uaCH.setUAData({ + "wow64" : true, + "formFactor" : "Automotive" +}); + +const headersData1 = uaCH.getSerializedUAData(); +const headersData2 = uaCH.getSerializedUAData(['brand', 'mobile', 'model']); + +console.log(headersData1); +/* + { + 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', + 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', + 'sec-ch-ua-arch' : 'arm', + 'sec-ch-ua-bitness' : '64', + 'sec-ch-ua-mobile' : '?1', + 'sec-ch-ua-model' : 'Pixel 99', + 'sec-ch-ua-platform' : 'Linux', + 'sec-ch-ua-platform-version' : '13', + 'sec-ch-ua-wow64' : '?1', + 'sec-ch-ua-form-factor' : 'Automotive' + }; +*/ + +console.log(headersData2); +/* + { + 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', + 'sec-ch-ua-mobile' : '?1', + 'sec-ch-ua-model' : 'Pixel 99' + }; +*/ +``` \ No newline at end of file diff --git a/src/ua-client-hints/ua-client-hints.d.ts b/src/ua-client-hints/ua-client-hints.d.ts new file mode 100644 index 0000000..3077658 --- /dev/null +++ b/src/ua-client-hints/ua-client-hints.d.ts @@ -0,0 +1,39 @@ +export type UABrowser = { + brand: string | null, + version: string | null +}; + +export type UADataType = boolean | string | Array | null; +export type UADataField = + 'brands' | + 'mobile' | + 'platform' | + 'architecture' | + 'bitness' | + 'formFactor' | + 'fullVersionList' | + 'model' | + 'platformVersion' | + 'wow64'; + +export type HeaderType = 'sf-boolean' | 'sf-string' | 'sf-list'; +export type HeaderField = + 'sec-ch-ua-arch' | + 'sec-ch-ua-bitness' | + 'sec-ch-ua' | + 'sec-ch-ua-form-factor' | + 'sec-ch-ua-full-version-list' | + 'sec-ch-ua-mobile' | + 'sec-ch-ua-model' | + 'sec-ch-ua-platform' | + 'sec-ch-ua-platform-version' | + 'sec-ch-ua-wow64'; + +export class UAClientHints { + #ch: Map; + #parseHeader(str: string, type: HeaderType): UADataType; + #serialize(data: UADataType, type: HeaderType): string; + getSerializedUAData(): Record; + getUAData(props?: Array): Record; + setUAData(uaData: Record | Record): UAClientHints; +}; \ No newline at end of file diff --git a/src/ua-client-hints/ua-client-hints.js b/src/ua-client-hints/ua-client-hints.js new file mode 100644 index 0000000..d4ddc60 --- /dev/null +++ b/src/ua-client-hints/ua-client-hints.js @@ -0,0 +1,130 @@ +////////////////////////////////////////////// +/* A collection of utility methods for + working with user-agent client hints + https://github.com/faisalman/ua-parser-js + Author: Faisal Salman + MIT License */ +///////////////////////////////////////////// + +/*jshint esversion: 11 */ + +const fieldType = Object.freeze({ + Boolean : 'sf-boolean', + List : 'sf-list', + String : 'sf-string' +}); + +const uaCHMap = Object.freeze({ + architecture : { + field : 'Sec-CH-UA-Arch', + type : fieldType.String + }, + bitness : { + field : 'Sec-CH-UA-Bitness', + type : fieldType.String + }, + brands : { + field : 'Sec-CH-UA', + type : fieldType.List + }, + formFactor : { + field : 'Sec-CH-UA-Form-Factor', + type : fieldType.String + }, + fullVersionList : { + field : 'Sec-CH-UA-Full-Version-List', + type : fieldType.List + }, + mobile : { + field : 'Sec-CH-UA-Mobile', + type : fieldType.Boolean + }, + model : { + field : 'Sec-CH-UA-Model', + type : fieldType.String + }, + platform : { + field : 'Sec-CH-UA-Platform', + type : fieldType.String + }, + platformVersion : { + field : 'Sec-CH-UA-Platform-Version', + type : fieldType.String + }, + wow64 : { + field : 'Sec-CH-UA-WOW64', + type : fieldType.Boolean + } +}); + +class UAClientHints { + + #uach = new Map(); + + constructor () { + for (const key in uaCHMap) { + this.#uach.set(key, null); + } + return this; + }; + + #parseHeader (str, type) { + if (!str) { + return null; + } + switch (type) { + case fieldType.Boolean: + return /\?1/.test(str); + case fieldType.List: + return str.replace(/\\?\"/g, '') + .split(',') + .map(brands => { + const [brand, version] = brands.trim().split(';v='); + return { + brand : brand, + version : version + }; + }); + case fieldType.String: + return str.replace(/\s*\\?\"\s*/g, ''); + default: + return ''; + } + }; + + #serialize(data, type) { + throw new Error('Not implemented yet'); + //return ''; + } + + getSerializedUAData() { + throw new Error('Not implemented yet'); + //let http = {}; + //return http; + } + + getUAData(props) { + if (props) { + return Object.fromEntries(props.filter(val => this.#uach.get(val)).map(val => [val, this.#uach.get(val)])); + } + return Object.fromEntries(this.#uach); + } + + setUAData(uaDataValues) { + if(Object.keys(uaDataValues).some(key => key.startsWith('sec-ch-ua'))) { + for (const val in uaCHMap) { + const { field, type } = uaCHMap[val]; + this.#uach.set(val, this.#parseHeader(uaDataValues[field.toLowerCase()], type)); + } + } else { + for (const value in uaDataValues) { + if (this.#uach.has(value)) this.#uach.set(value, uaDataValues[value]); + } + } + return this; + }; +} + +module.exports = { + UAClientHints +}; \ No newline at end of file diff --git a/src/ua-client-hints/ua-client-hints.mjs b/src/ua-client-hints/ua-client-hints.mjs new file mode 100644 index 0000000..047f5c8 --- /dev/null +++ b/src/ua-client-hints/ua-client-hints.mjs @@ -0,0 +1,134 @@ +// Generated ESM version of @ua-parser-js/ua-client-hints +// DO NOT EDIT THIS FILE! +// Source: /src/ua-client-hints/ua-client-hints.js + +////////////////////////////////////////////// +/* A collection of utility methods for + working with user-agent client hints + https://github.com/faisalman/ua-parser-js + Author: Faisal Salman + MIT License */ +///////////////////////////////////////////// + +/*jshint esversion: 11 */ + +const fieldType = Object.freeze({ + Boolean : 'sf-boolean', + List : 'sf-list', + String : 'sf-string' +}); + +const uaCHMap = Object.freeze({ + architecture : { + field : 'Sec-CH-UA-Arch', + type : fieldType.String + }, + bitness : { + field : 'Sec-CH-UA-Bitness', + type : fieldType.String + }, + brands : { + field : 'Sec-CH-UA', + type : fieldType.List + }, + formFactor : { + field : 'Sec-CH-UA-Form-Factor', + type : fieldType.String + }, + fullVersionList : { + field : 'Sec-CH-UA-Full-Version-List', + type : fieldType.List + }, + mobile : { + field : 'Sec-CH-UA-Mobile', + type : fieldType.Boolean + }, + model : { + field : 'Sec-CH-UA-Model', + type : fieldType.String + }, + platform : { + field : 'Sec-CH-UA-Platform', + type : fieldType.String + }, + platformVersion : { + field : 'Sec-CH-UA-Platform-Version', + type : fieldType.String + }, + wow64 : { + field : 'Sec-CH-UA-WOW64', + type : fieldType.Boolean + } +}); + +class UAClientHints { + + #uach = new Map(); + + constructor () { + for (const key in uaCHMap) { + this.#uach.set(key, null); + } + return this; + }; + + #parseHeader (str, type) { + if (!str) { + return null; + } + switch (type) { + case fieldType.Boolean: + return /\?1/.test(str); + case fieldType.List: + return str.replace(/\\?\"/g, '') + .split(',') + .map(brands => { + const [brand, version] = brands.trim().split(';v='); + return { + brand : brand, + version : version + }; + }); + case fieldType.String: + return str.replace(/\s*\\?\"\s*/g, ''); + default: + return ''; + } + }; + + #serialize(data, type) { + throw new Error('Not implemented yet'); + //return ''; + } + + getSerializedUAData() { + throw new Error('Not implemented yet'); + //let http = {}; + //return http; + } + + getUAData(props) { + if (props) { + return Object.fromEntries(props.filter(val => this.#uach.get(val)).map(val => [val, this.#uach.get(val)])); + } + return Object.fromEntries(this.#uach); + } + + setUAData(uaDataValues) { + if(Object.keys(uaDataValues).some(key => key.startsWith('sec-ch-ua'))) { + for (const val in uaCHMap) { + const { field, type } = uaCHMap[val]; + this.#uach.set(val, this.#parseHeader(uaDataValues[field.toLowerCase()], type)); + } + } else { + for (const value in uaDataValues) { + if (this.#uach.has(value)) this.#uach.set(value, uaDataValues[value]); + } + } + return this; + }; +} + +export { + UAClientHints +}; \ No newline at end of file diff --git a/test/mocha-test-helpers.js b/test/mocha-test-helpers.js index 526887d..2c0b39f 100644 --- a/test/mocha-test-helpers.js +++ b/test/mocha-test-helpers.js @@ -1,5 +1,5 @@ const { isFrozenUA, unfreezeUA } = require('@ua-parser-js/user-agent-helpers'); -const { UACHParser } = require('@ua-parser-js/client-hints-helpers'); +const { UAClientHints } = require('@ua-parser-js/ua-client-hints'); const assert = require('assert'); describe('isFrozenUA()', () => { @@ -38,12 +38,12 @@ describe('isFrozenUA()', () => { const headers = { 'sec-ch-ua' : '"Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"', 'sec-ch-ua-full-version-list' : '"Chromium";v="93.0.1.2", "Google Chrome";v="93.0.1.2", " Not;A Brand";v="99.0.1.2"', - 'sec-ch-ua-arch' : 'arm', - 'sec-ch-ua-bitness' : '64', + 'sec-ch-ua-arch' : '"arm"', + 'sec-ch-ua-bitness' : '"64"', 'sec-ch-ua-mobile' : '?1', - 'sec-ch-ua-model' : 'Pixel 99', - 'sec-ch-ua-platform' : 'Linux', - 'sec-ch-ua-platform-version' : '13', + 'sec-ch-ua-model' : '"Pixel 99"', + 'sec-ch-ua-platform' : '"Linux"', + 'sec-ch-ua-platform-version' : '"13"', 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' }; @@ -54,9 +54,13 @@ describe('unfreezeUA()', () => { }); }); -describe('UACHParser()', () => { +describe('Parse CH Headers', () => { it('parse client hints HTTP headers (sec-ch-ua) into a client hints-like JavaScript object', () => { - assert.deepEqual(UACHParser(headers), { + assert.deepEqual(new UAClientHints().setUAData(headers).getUAData(['architecture', 'bitness']), { + "architecture": "arm", + "bitness": "64" + }); + assert.deepEqual(new UAClientHints().setUAData(headers).getUAData(), { "architecture": "arm", "bitness": "64", "brands": [ @@ -69,7 +73,7 @@ describe('UACHParser()', () => { "version": "93" }, { - "brand": " Not;A Brand", + "brand": "Not;A Brand", "version": "99" } ], @@ -83,14 +87,16 @@ describe('UACHParser()', () => { "version": "93.0.1.2" }, { - "brand": " Not;A Brand", + "brand": "Not;A Brand", "version": "99.0.1.2" } ], + "formFactor": null, "mobile": true, "model": "Pixel 99", "platform": "Linux", - "platformVersion": "13" + "platformVersion": "13", + "wow64": null }); }); }); \ No newline at end of file