This commit is contained in:
2021-11-16 11:20:33 +01:00
commit 8770b1fa2a
14 changed files with 2174 additions and 0 deletions

50
src/utils/caniuse.ts Normal file
View File

@@ -0,0 +1,50 @@
import DeviceDetector from 'device-detector-js'
import Avif from 'caniuse-db/features-json/avif.json'
import WebP from 'caniuse-db/features-json/webp.json'
const detector = new DeviceDetector()
function findLowestCompatibleVersion(stat: Record<string, string>): string {
const entries = Object.entries(stat).sort((a, b) => parseInt(a[0]) - parseInt(b[0]))
for (const [version, support] of entries) {
if (support.startsWith('y') || support.startsWith('a')) {
return version
}
}
}
const mapping = {
'Internet Explorer': 'ie',
'Microsoft Edge': 'edge',
Firefox: 'firefox',
Chrome: 'chrome',
Safari: 'safari',
Opera: 'opera',
'Mobile Safari': 'ios_saf',
'Opera Mini': 'op_mini',
'Android Browser': 'android',
'Chrome Mobile': 'and_chr',
'Firefox Mobile': 'and_ff',
'UC Browser': 'and_uc',
'Samsung Browser': 'samsung',
'QQ Browser': 'and_qq',
}
function matchBrowserToStat(browser: DeviceDetector.DeviceDetectorResult): string {
if (!browser.os || !browser.client) throw new Error('Invalid browser')
if (browser.os.name === 'iOS') {
return 'ios_saf'
}
if (browser.os.name in mapping) {
return mapping[browser.os.name as keyof typeof mapping]
}
throw new Error('Could not determine mapping for browser')
}
function match(feature: typeof Avif | typeof WebP, ua: string): boolean {
const browser = detector.parse(ua)
const stats = feature.stats[matchBrowserToStat(browser) as keyof typeof feature.stats]
console.debug(stats)
console.debug(findLowestCompatibleVersion(stats))
return false
}

39
src/utils/utils.ts Normal file
View File

@@ -0,0 +1,39 @@
import { createHash } from 'crypto'
import { validateSync, ValidatorOptions, ValidationError as VE } from 'class-validator'
import { PassThrough, Readable } from 'stream'
export class ValidationError extends Error {
override message: string
constructor(errors: VE[]) {
super()
this.message = errors
.map((e) => Object.values(e.constraints!))
.flat()
.join(', ')
}
}
export function validateSyncOrFail(data: object, options: ValidatorOptions = {}) {
options = Object.assign({ whitelist: true, forbidUnknownValues: true, skipMissingProperties: false }, options)
const errors = validateSync(data, options)
if (errors.length > 0) {
throw new ValidationError(errors)
}
}
export function sha3(url: string) {
return createHash('sha3-256').update(url).digest('hex')
}
export function sortObjectByKeys<T extends object>(obj: T): T {
return Object.fromEntries(Object.entries(obj).sort((a, b) => a[0].localeCompare(b[0]))) as T
}
export function splitter(from: NodeJS.ReadableStream, ...streams: NodeJS.WritableStream[]) {
const splitter = new PassThrough()
for (const stream of streams) {
splitter.pipe(stream)
}
from.pipe(splitter)
}