2.1
Alur Parsing User-Agent dan Client Hints
Satu pemanggilan new UAParser(...).getResult() melewati empat lapis kerja. UAParser menyiapkan masukan, UAItem.parseUA mengisi field dari string User-Agent, UAItem.parseCH menimpanya dengan client hints, lalu UAItem.detectFeature menambal sisa field dari kemampuan browser. Semua lapis menulis ke IData yang sama, sehingga urutan pemanggilan menentukan nilai akhir. Bentuk field hasilnya dibahas di Model Data Hasil dan Enums.
Konstruktor memilih masukan
UAParser(ua, extensions, headers) menerima tiga bentuk argumen. Bila argumen pertama sebuah object, konstruktor memutuskan apakah itu extensions atau headers. Bila argumen pertama string dan argumen kedua bukan extensions, argumen kedua diperlakukan sebagai headers src/main/ua-parser.js:1422-14381.
Headers dinormalkan sebelum dipakai. Bila object headers punya metode append, isinya disalin ke object biasa dengan key lowercase. Bila tidak, key di-lowercase dan nilai berbentuk array digabung dengan ', ' src/main/ua-parser.js:1440-14572.
String User-Agent diambil berurutan: argumen ua bila string, lalu headers['user-agent'], lalu navigator.userAgent, dan terakhir string kosong src/main/ua-parser.js:1463-14663.
| Nilai | Asal | Rujukan |
|---|---|---|
userAgent | argumen ua, headers['user-agent'], navigator.userAgent, atau '' | src/main/ua-parser.js:1463-14663 |
httpUACH | new UACHData(headers, true) | src/main/ua-parser.js:1468-14694 |
regexMap | defaultRegexes, lalu useExtension(extensions) | src/main/ua-parser.js:1468-14694 dan src/main/ua-parser.js:1505-15085 |
userAgent akhir | setUA(userAgent) memotong ke UA_MAX_LENGTH = 500 | src/main/ua-parser.js:1501-15046 dan src/main/ua-parser.js:22-237 |
UACHData(headers, true) membaca header sec-ch-ua, sec-ch-ua-full-version-list, sec-ch-ua-mobile (diuji dengan /\?1/), sec-ch-ua-model, sec-ch-ua-platform, sec-ch-ua-platform-version, sec-ch-ua-arch, sec-ch-ua-form-factors, dan sec-ch-ua-bitness. Nama field yang dipakai adalah isi CH_ALL_VALUES src/main/ua-parser.js:63-798 dan src/main/ua-parser.js:1204-12239.
getResult merangkai lima item
createItemFunc(RESULT) membuat UAItem(RESULT, userAgent, regexMap, httpUACH), menulis 'ua', lalu memanggil this.getBrowser(), getCPU(), getDevice(), getEngine(), dan getOS() untuk mengisi IResult src/main/ua-parser.js:1471-149010. Tiap item getter membuat UAItem(itemType, userAgent, regexMap[itemType], httpUACH) dan langsung menjalankan parseUA() src/main/ua-parser.js:1483-148811.
sequenceDiagram
participant C as Pemanggil
participant P as UAParser
participant R as UAItem RESULT
participant I as UAItem per itemType
participant M as rgxMapper
C->>P: new UAParser ua extensions headers
P->>P: normalisasi headers dan pemilihan userAgent
P->>P: setUA userAgent dan useExtension extensions
C->>P: getResult
P->>R: new UAItem RESULT userAgent regexMap httpUACH
loop browser lalu cpu device engine os
R->>R: this.getBrowser dan seterusnya
R->>I: new UAItem itemType userAgent regexMap itemType httpUACH
I->>M: parseUA memanggil rgxMapper pada data
M-->>I: data terisi name version major type
I-->>R: get mengembalikan IData
R->>R: set itemType ke data IResult
end
R-->>C: IResult siap
%% fig: Siklus getResult sampai IResult
%% desc: Konstruktor menyiapkan masukan, lalu getResult membuat satu UAItem RESULT yang memanggil lima item getter dan masing-masing menjalankan parseUA lewat rgxMapper.Field awal tiap item ditentukan defaultProps.init. Browser memakai [name, version, major, type], CPU memakai [architecture], device memakai [type, model, vendor], engine dan OS memakai [name, version] src/main/ua-parser.js:1087-109312. createIData membungkusnya menjadi IData dan menyediakan getItem(), withClientHints(), serta withFeatureCheck() src/main/ua-parser.js:1113-115013. Konstruktor UAItem sendiri hanya menyimpan itemType, ua, uaCH, rgxMap, dan data src/main/ua-parser.js:1226-123514.
UAItem.parseUA mengisi field dari string UA
Untuk semua itemType selain result, parseUA memanggil rgxMapper.call(this.data, this.ua, this.rgxMap) src/main/ua-parser.js:1296-131815. rgxMapper menelusuri pasangan array regex dan daftar prop, berhenti pada match pertama, lalu menulis nilai ke this.data sesuai bentuk prop (string, pasangan [nama, nilai], atau mapper fungsi/regex) src/main/ua-parser.js:218-23516.
itemType | Tambahan setelah rgxMapper | Rujukan |
|---|---|---|
| lainnya | hanya hasil rgxMapper | src/main/ua-parser.js:1297-129917 |
browser | set(MAJOR, majorize(version)) | src/main/ua-parser.js:1301-130318 |
os | bila versi iOS dimulai 18 atau 19, versi diambil ulang dari ) Version/ ketika angka mayor versi Safari minimal 26 | src/main/ua-parser.js:1305-131519 |
UAItem.parseCH menimpa field dengan client hints
parseCH tidak dipanggil oleh getResult(); ia baru berjalan lewat withClientHints() atau lewat cabang result di dalam parseCH itu sendiri src/main/ua-parser.js:1128-114620. Karena itu pemanggilan tanpa withClientHints() hanya membaca header User-Agent test/unit/ua-ch.js:54-6021.
sequenceDiagram
participant C as Pemanggil
participant D as IData
participant I as UAItem
participant N as navigator.userAgentData
participant U as UACHData
C->>D: withClientHints
alt NAVIGATOR_UADATA tidak tersedia
D->>I: parseCH dengan uaCH dari httpUACH
I-->>C: IData hasil parseCH
else Chromium 85 ke atas
D->>N: getHighEntropyValues CH_ALL_VALUES
N-->>D: res
D->>U: new UACHData res false
D->>I: setCH lalu parseCH
I-->>C: Promise berisi IData
end
%% fig: Dua jalur withClientHints
%% desc: Tanpa navigator.userAgentData parseCH langsung dijalankan memakai httpUACH, sedangkan Chromium 85 ke atas menunggu getHighEntropyValues lebih dulu.Pada cabang result, tiap item diambil lewat getItem(), lalu setCH(uaCH), parseCH(), dan get(). Instance UAItem-nya sama dengan hasil parseUA, sehingga field yang sudah terisi hanya berubah bila client hints menulis nilai baru src/main/ua-parser.js:1404-141722.
itemType | Sumber di uaCH | Tindakan | Rujukan |
|---|---|---|---|
browser, engine | fullVersionList lalu brands | menelusuri brand, melewati /not.a.brand/i, memetakan nama lewat browserHintsMap, mengisi name/version/major; pada engine hanya brand Chromium yang mengisi version | src/main/ua-parser.js:1320-135123 |
cpu | architecture, bitness | menambah akhiran 64 bila bitness bernilai 64, lalu rgxMapper dengan string archName + ';' | src/main/ua-parser.js:1353-135924 |
device | mobile, model, formFactors | mengisi type mobile, mengisi model, parse ulang 'droid 9; ' + model + ')' untuk type dan vendor, lalu memetakan formFactors lewat formFactorsMap | src/main/ua-parser.js:1360-138925 |
os | platform, platformVersion | mengisi name/version; untuk Windows angka mayor minimal 13 menjadi '11', selebihnya '10'; bila model bernilai Xbox, name menjadi Xbox dan version menjadi undefined | src/main/ua-parser.js:1390-140326 |
Pemetaan nilai memakai dua tabel statis: browserHintsMap untuk nama browser dan formFactorsMap untuk tipe perangkat, yang memetakan embedded, mobile, tablet, smarttv, wearable, xr, dan ? src/main/ua-parser.js:320-34127.
UAItem.detectFeature menambal dari kemampuan browser
detectFeature hanya bekerja bila NAVIGATOR.userAgent sama dengan this.ua yang sedang di-parse src/main/ua-parser.js:1252-129428. Di luar kondisi itu IData tidak berubah, sehingga di Node.js fungsi ini praktis tidak berefek.
graph TD
START["detectFeature"] --> GUARD{"NAVIGATOR.userAgent == this.ua"}
GUARD -- "tidak" --> SKIP["IData tidak berubah"]
GUARD -- "ya" --> SW{"itemType"}
SW -- "browser" --> BR["navigator.brave.isBrave -> name Brave"]
SW -- "device" --> DEV["userAgentData.mobile -> type mobile | maxTouchPoints > 2 -> model iPad dan type tablet"]
SW -- "os" --> OS["userAgentData.platform -> name"]
SW -- "result" --> RES["detect tiap item lalu set ke IResult"]
style START fill:#f59e0b,color:#000
style GUARD fill:#f59e0b,color:#000
style SKIP fill:#dc2626,color:#fff
style BR fill:#2d7d46,color:#fff
style DEV fill:#2d7d46,color:#fff
style OS fill:#2d7d46,color:#fff
style RES fill:#8b5cf6,color:#fff
%% fig: Guard dan cabang detectFeature
%% desc: detectFeature berjalan hanya bila string UA yang di-parse sama dengan navigator.userAgent, lalu mengoreksi per itemType memakai API browser.Cabang device mengisi type mobile dari navigator.userAgentData bila type masih kosong. Bila model bernilai Macintosh dan navigator.maxTouchPoints lebih dari 2 sementara navigator.standalone terdefinisi, model diubah menjadi iPad dan type menjadi tablet src/main/ua-parser.js:1261-127129. Cabang os mengisi name dari userAgentData.platform bila hasil parseUA belum punya nama src/main/ua-parser.js:1272-127730.
⚠️
withClientHints()mengembalikanPromisedi Chromium 85+ tetapi objekIDatabiasa di Node.js dan browser tanpanavigator.userAgentData.IData.prototype.thenmembuat kedua bentuk itu bisa dirangkai dengan.then(), namun kode yang memakaiawaitperlu memperhitungkan bahwa nilainya baru terisi setelah promise selesai src/main/ua-parser.js:1177-119531.
Berkas .mjs mengikuti alur yang sama
src/main/ua-parser.mjs adalah versi ESM hasil bangkitan dari src/main/ua-parser.js; berkas itu menyatakan dirinya tidak boleh diedit langsung dan hanya menambahkan export {UAParser} di akhir berkas src/main/ua-parser.mjs:1-332 dan src/main/ua-parser.mjs:151933. Alur UAParser, parseUA, parseCH, dan detectFeature identik, hanya nomor barisnya bergeser beberapa baris. Rincian API pemanggilnya ada di API UAParser.