Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[astro-useragent] Upgrade ua-parser-js to v2 #751

Merged
merged 5 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/rotten-teachers-join.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro-useragent': minor
---

Upgrade ua-parser-js to v2
1 change: 0 additions & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ jobs:

- run: pnpm run test
- run: pnpm run build
- run: pnpx pkg-pr-new publish './packages/astro-purgecss'
23 changes: 23 additions & 0 deletions .github/workflows/pkgpr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Publish packages
on: [pull_request]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"

- name: Install dependencies
run: pnpm install

- name: Build
run: pnpm build

- run: pnpx pkg-pr-new publish './packages/astro-purgecss' './packages/astro-useragent'
54 changes: 32 additions & 22 deletions packages/astro-useragent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Astro UserAgent is a simple helper for parsing `user-agent` header strings for browser matching inside your Astro Pages / API routes, when using [SSR Mode][astro-ssr]

> **Note** Due to the nature of Astro being an SSG by trade, This package only works when used with astro in [SSR Mode][astro-ssr].
> **Note** Due to the nature of Astro being an SSG by trade, This package only works when used with Astro in [SSR Mode][astro-ssr].

## 📦 Installation

Expand Down Expand Up @@ -112,31 +112,42 @@ The parsed `UserAgent` object will have the following interface:

```typescript
export interface UserAgent {
readonly source: string; // original user agent string.
readonly source: string | null; // The original user agent string.
readonly browser: string | null;
readonly browserVersion: number;
readonly cpu: string | null;
readonly deviceType: string | null;
readonly deviceVendor: string | null;
readonly os: string;
readonly osVersion: number;
readonly browser: string;
readonly browserVersion: number;
readonly engine: string;
readonly engineVersion: number;
readonly isIphone: boolean;
readonly isIpad: boolean;
readonly isMobile: boolean;
readonly isTablet: boolean;
readonly isDesktop: boolean;
readonly engine: string | null;
readonly engineVersion: number | null;
readonly os: string | null;
readonly osVersion: number | null;
readonly isAndroid: boolean;
readonly isChrome: boolean;
readonly isChromeOS: boolean;
readonly isDesktop: boolean;
readonly isEdge: boolean;
readonly isFirefox: boolean;
readonly isSafari: boolean;
readonly isIE: boolean;
readonly isEdge: boolean;
readonly isOpera: boolean;
readonly isIos: boolean;
readonly isIpad: boolean;
readonly isIphone: boolean;
readonly isMac: boolean;
readonly isChromeOS: boolean;
readonly isMobile: boolean;
readonly isOpera: boolean;
readonly isSafari: boolean;
readonly isTablet: boolean;
readonly isWindows: boolean;
readonly isIos: boolean;
readonly isAndroid: boolean;
readonly isBot: boolean;
readonly isAIBot: boolean;
readonly isChromeFamily: boolean;
readonly isAppleSilicon: boolean;
getUA(): string;
getBrowser(): IBrowser;
getCPU(): ICPU;
getDevice(): IDevice;
getEngine(): IEngine;
getOS(): IOS;
}
```

Expand All @@ -157,12 +168,11 @@ Please see the [Changelog](CHANGELOG.md) for more information on what has change

## Acknowledgements

`astro-useragent` is a port from [next-useragent][next-useragent] to Astro. so big thanks to [Tsuyoshi Tokuda][tokuda109] and the contributors behind next-useragent package.
`astro-useragent` is a port from [next-useragent][next-useragent] to Astro. so big thanks to the contributors behind next-useragent package.

[astro-ssr]: https://docs.astro.build/en/guides/server-side-rendering
[npm]: https://npmjs.com/package/astro-useragent
[next-useragent]: https://github.com/tokuda109/next-useragent
[tokuda109]: https://github.com/tokuda109
[next-useragent]: https://github.com/warent/next-useragent

<!-- Readme Badges -->

Expand Down
21 changes: 12 additions & 9 deletions packages/astro-useragent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,33 @@
"directory": "packages/astro-useragent"
},
"scripts": {
"build": "astro-build --src src/index.ts src/parse.ts src/useUserAgent.ts",
"typecheck": "tsc --declaration --emitDeclarationOnly"
"build": "tsup",
"check-types": "tsc",
"check-exports": "attw --pack . --ignore-rules false-export-default",
"typecheck": "pnpm check-types && pnpm check-exports"
},
"type": "module",
"types": "dist/index.d.ts",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"main": "./dist/index.mjs",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"dependencies": {
"ua-parser-js": "^2.0.0"
},
"devDependencies": {
"astro-build": "workspace:*",
"@types/ua-parser-js": "^0.7.36"
},
"peerDependencies": {
"astro": "^4.0.0"
}
Expand Down
148 changes: 94 additions & 54 deletions packages/astro-useragent/src/parse.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,113 @@
import { UAParser } from 'ua-parser-js';
import {
UAParser,
type IBrowser,
type ICPU,
type IDevice,
type IEngine,
type IOS
} from 'ua-parser-js';

import {
isAIBot,
isAppleSilicon,
isBot,
isChromeFamily
} from 'ua-parser-js/helpers';

// mostly ported from https://github.com/tokuda109/next-useragent
export interface UserAgent {
// The original user agent string.
readonly source: string;
readonly source: string | null; // The original user agent string.
readonly browser: string | null;
readonly browserVersion: number;
readonly cpu: string | null;
readonly deviceType: string | null;
readonly deviceVendor: string | null;
readonly os: string;
readonly osVersion: number;
readonly browser: string;
readonly browserVersion: number;
readonly engine: string;
readonly engineVersion: number;
readonly isIphone: boolean;
readonly isIpad: boolean;
readonly isMobile: boolean;
readonly isTablet: boolean;
readonly isDesktop: boolean;
readonly engine: string | null;
readonly engineVersion: number | null;
readonly os: string | null;
readonly osVersion: number | null;
readonly isAndroid: boolean;
readonly isChrome: boolean;
readonly isChromeOS: boolean;
readonly isDesktop: boolean;
readonly isEdge: boolean;
readonly isFirefox: boolean;
readonly isSafari: boolean;
readonly isIE: boolean;
readonly isEdge: boolean;
readonly isOpera: boolean;
readonly isIos: boolean;
readonly isIpad: boolean;
readonly isIphone: boolean;
readonly isMac: boolean;
readonly isChromeOS: boolean;
readonly isMobile: boolean;
readonly isOpera: boolean;
readonly isSafari: boolean;
readonly isTablet: boolean;
readonly isWindows: boolean;
readonly isIos: boolean;
readonly isAndroid: boolean;
readonly isBot: boolean;
readonly isAIBot: boolean;
readonly isChromeFamily: boolean;
readonly isAppleSilicon: boolean;
getUA(): string;
getBrowser(): IBrowser;
getCPU(): ICPU;
getDevice(): IDevice;
getEngine(): IEngine;
getOS(): IOS;
}

export const parse = (uastring: string | null): UserAgent => {
const ua = uastring ?? '';
const result: UAParser.IResult = new UAParser(ua).getResult();
export const parse = (ua: string | null): UserAgent => {
const uap = new UAParser(ua ?? '');

const browser: string = result.browser.name || '';
const deviceType: string = result.device.type || '';
const os: string = result.os.name || '';
const engine: string = result.engine.name || '';
const isMobile: boolean = deviceType === 'mobile';
const isTablet: boolean = deviceType === 'tablet';
const isIos: boolean = os === 'iOS';
const browser = uap.getBrowser();
const cpu = uap.getCPU();
const device = uap.getDevice();
const engine = uap.getEngine();
const os = uap.getOS();

const userAgent: UserAgent = Object.freeze({
browser,
deviceType,
os,
engine,
isMobile,
isTablet,
isIos,
source: ua,
deviceVendor: result.device.vendor || null,
osVersion: parseInt(result.os.version || '0', 10),
browserVersion: parseFloat(result.browser.version || '0'),
engineVersion: parseFloat(result.engine.version || '0'),
isIphone: isMobile && isIos,
isIpad: isTablet && isIos,
isDesktop: !isMobile && !isTablet,
isChrome: browser === 'Chrome',
isFirefox: browser === 'Firefox',
isSafari: browser === 'Safari',
isIE: browser === 'IE',
isEdge: browser === 'Edge',
isOpera: browser === 'Opera',
isMac: os === 'Mac OS',
isChromeOS: os === 'Chromium OS',
isWindows: os === 'Windows',
isAndroid: os === 'Android'
browser: browser.name || null,
browserVersion: parseFloat(browser.version || '0'),
cpu: cpu.architecture || null,
deviceType: device.type || 'mobile',
deviceVendor: device.vendor || null,
engine: engine.name || null,
engineVersion: parseFloat(engine.version || '0'),
os: os.name || null,
osVersion: parseInt(os.version || '0', 10),
isAndroid: os.is('Android') || os.is('Android-x86'),
isChrome: browser.is('Chrome') || browser.is('Chrome Mobile'),
isChromeOS: os.is('Chrome OS'),
isDesktop: !device.is('mobile') && !device.is('tablet'),
isEdge: browser.is('Edge'),
isFirefox: browser.is('Firefox') || browser.is('Firefox Mobile'),
isIE: browser.is('IE') || browser.is('IEMobile'),
isIos: os.is('iOS'),
isIpad: device.is('tablet') && os.is('iOS'),
isIphone: device.is('mobile') && os.is('iOS'),
isMac: os.is('macOS'),
isMobile: device.is('mobile'),
isOpera:
browser.is('Opera') ||
browser.is('Opera GX') ||
browser.is('Opera Mini') ||
browser.is('Opera Mobi') ||
browser.is('Opera Tablet'),
isSafari: browser.is('Safari') || browser.is('Safari Mobile'),
isTablet: device.is('tablet'),
isWindows:
os.is('Windows') || os.is('Windows Phone') || os.is('Windows Mobile'),
isBot: isBot(ua ?? ''),
isAIBot: isAIBot(ua ?? ''),
isChromeFamily: isChromeFamily(ua ?? ''),
isAppleSilicon: isAppleSilicon(ua ?? ''),

// methods
getBrowser: uap.getBrowser,
getCPU: uap.getCPU,
getDevice: uap.getDevice,
getEngine: uap.getEngine,
getOS: uap.getOS,
getUA: uap.getUA
});

return userAgent;
Expand Down
2 changes: 1 addition & 1 deletion packages/astro-useragent/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"noEmit": false,
"noEmit": true,
"outDir": "./dist",
"allowImportingTsExtensions": false
}
Expand Down
14 changes: 14 additions & 0 deletions packages/astro-useragent/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig } from 'tsup';

export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outDir: 'dist',
clean: true,
dts: true,
minify: true,
sourcemap: true,
splitting: false,
treeshake: true,
platform: 'node'
});
12 changes: 0 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading