9b395f5cc3
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
Build Chrome Extension / build (push) Has been cancelled
Trigger Website Rebuild (Docs Updated) / dispatch (push) Has been cancelled
71 lines
2.2 KiB
JavaScript
71 lines
2.2 KiB
JavaScript
import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
|
|
|
|
export function requireSearchQuery(value, label = 'keyword') {
|
|
const query = String(value ?? '').trim();
|
|
if (!query) {
|
|
throw new ArgumentError(`${label} cannot be empty`);
|
|
}
|
|
return query;
|
|
}
|
|
|
|
export function requireBoundedInteger(value, defaultValue, min, max, label) {
|
|
const raw = value ?? defaultValue;
|
|
const parsed = typeof raw === 'number' ? raw : Number(raw);
|
|
if (!Number.isInteger(parsed)) {
|
|
throw new ArgumentError(`${label} must be an integer between ${min} and ${max}, got ${JSON.stringify(value)}`);
|
|
}
|
|
if (parsed < min || parsed > max) {
|
|
throw new ArgumentError(`${label} must be between ${min} and ${max}, got ${parsed}`);
|
|
}
|
|
return parsed;
|
|
}
|
|
|
|
export function requireNonNegativeInteger(value, defaultValue, label) {
|
|
const raw = value ?? defaultValue;
|
|
const parsed = typeof raw === 'number' ? raw : Number(raw);
|
|
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
throw new ArgumentError(`${label} must be a non-negative integer, got ${JSON.stringify(value)}`);
|
|
}
|
|
return parsed;
|
|
}
|
|
|
|
export function unwrapBrowserResult(value) {
|
|
if (value && typeof value === 'object' && !Array.isArray(value) && 'session' in value && 'data' in value) {
|
|
return value.data;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function requireRows(value, label) {
|
|
const rows = unwrapBrowserResult(value);
|
|
if (!Array.isArray(rows)) {
|
|
throw new CommandExecutionError(`${label} returned an unexpected payload shape; expected an array of result rows.`);
|
|
}
|
|
return rows;
|
|
}
|
|
|
|
export function toHttpsUrl(value, baseUrl) {
|
|
const raw = String(value ?? '').trim();
|
|
if (!raw) return '';
|
|
try {
|
|
const url = new URL(raw, baseUrl);
|
|
if (url.protocol !== 'http:' && url.protocol !== 'https:') return '';
|
|
return url.href;
|
|
} catch {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
export function emptySearchResults(site, query) {
|
|
return new EmptyResultError(`${site} search`, `No ${site} results matched "${query}".`);
|
|
}
|
|
|
|
export async function runBrowserStep(label, fn) {
|
|
try {
|
|
return await fn();
|
|
} catch (error) {
|
|
if (error?.code || error?.name === 'ArgumentError') throw error;
|
|
throw new CommandExecutionError(`${label} failed: ${error?.message ?? error}`);
|
|
}
|
|
}
|