|
| 1 | +#!/usr/bin/env bun |
| 2 | + |
| 3 | +const routeGroups = { |
| 4 | + topLevel: [ |
| 5 | + '/', |
| 6 | + '/categories', |
| 7 | + '/devices', |
| 8 | + '/benchmarks', |
| 9 | + '/games', |
| 10 | + '/apple-silicon-app-test' |
| 11 | + ], |
| 12 | + dynamic: [ |
| 13 | + '/app/kicad-eda', |
| 14 | + '/app/spotify', |
| 15 | + '/formula/bash', |
| 16 | + '/kind/developer-tools', |
| 17 | + '/device/m1-imac', |
| 18 | + '/app/expressvpn/benchmarks' |
| 19 | + ], |
| 20 | + video: [ |
| 21 | + '/tv/apple-silicon-gaming-is-here', |
| 22 | + '/tv/install-instagram-app-on-m1-macbook-air-apple-silicon-tutorial-i-vfbmworal6i', |
| 23 | + '/tv/xamarin-and-visual-studio-on-apple-macbook-pro-13-m1-in-4k-i-rwpspmmlos', |
| 24 | + '/tv/watch-this-before-buying-apple-m1-macbook-for-xampp-or-apple-silicon-tests-in-4k-i-ebwwewsis8s' |
| 25 | + ] |
| 26 | +} |
| 27 | + |
| 28 | +function parseHosts(rawHosts) { |
| 29 | + const source = rawHosts && rawHosts.trim().length > 0 |
| 30 | + ? rawHosts |
| 31 | + : 'doesitarm.com' |
| 32 | + |
| 33 | + return source |
| 34 | + .split(',') |
| 35 | + .map(host => host.trim()) |
| 36 | + .filter(Boolean) |
| 37 | + .map(host => host.startsWith('http://') || host.startsWith('https://') ? host : `https://${host}`) |
| 38 | +} |
| 39 | + |
| 40 | +function getPaths() { |
| 41 | + return Object.values(routeGroups).flat() |
| 42 | +} |
| 43 | + |
| 44 | +function extractTitle(html) { |
| 45 | + const match = html.match(/<title>([^<]+)<\/title>/i) |
| 46 | + |
| 47 | + return match ? match[1].trim() : '' |
| 48 | +} |
| 49 | + |
| 50 | +async function runCheck(host, path) { |
| 51 | + const url = new URL(path, host) |
| 52 | + const response = await fetch(url, { |
| 53 | + redirect: 'follow', |
| 54 | + headers: { |
| 55 | + 'user-agent': 'doesitarm-health-check' |
| 56 | + } |
| 57 | + }) |
| 58 | + |
| 59 | + const html = await response.text() |
| 60 | + const finalUrl = response.url |
| 61 | + |
| 62 | + return { |
| 63 | + host: new URL(host).host, |
| 64 | + path, |
| 65 | + status: response.status, |
| 66 | + ok: response.ok, |
| 67 | + finalPath: new URL(finalUrl).pathname, |
| 68 | + title: extractTitle(html) |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +const hosts = parseHosts(process.argv[2] || '') |
| 73 | +const paths = getPaths() |
| 74 | + |
| 75 | +console.log(`Checking ${paths.length} routes across ${hosts.length} host(s)`) |
| 76 | + |
| 77 | +let hasFailures = false |
| 78 | + |
| 79 | +for (const host of hosts) { |
| 80 | + console.log(`\nHost: ${new URL(host).host}`) |
| 81 | + |
| 82 | + const results = await Promise.all(paths.map(path => runCheck(host, path))) |
| 83 | + |
| 84 | + for (const result of results) { |
| 85 | + const statusLabel = result.ok ? 'PASS' : 'FAIL' |
| 86 | + const redirectSuffix = result.finalPath !== result.path ? ` -> ${result.finalPath}` : '' |
| 87 | + const titleSuffix = result.title.length > 0 ? ` | ${result.title}` : '' |
| 88 | + |
| 89 | + console.log(`${statusLabel} ${result.status} ${result.path}${redirectSuffix}${titleSuffix}`) |
| 90 | + } |
| 91 | + |
| 92 | + const failures = results.filter(result => !result.ok) |
| 93 | + |
| 94 | + if (failures.length > 0) { |
| 95 | + hasFailures = true |
| 96 | + console.log(`Failures: ${failures.length}`) |
| 97 | + } else { |
| 98 | + console.log('Failures: 0') |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +if (hasFailures) { |
| 103 | + process.exit(1) |
| 104 | +} |
0 commit comments