/** * @jobo-ai/scraper-sdk/validation * * Shared validation logic for job listings and details. * Used by the SDK test runner and the production scraper runtime to enforce * minimum data-quality requirements before a job is considered valid. * * Import from '@jobo-ai/scraper-sdk/validation' in your code. */ /** * Minimum shape a listing must satisfy for validation. * Intentionally loose so both SDK models and runtime types can be passed in. */ interface ValidatableJobListing { externalId?: string | null; title?: string | null; applyUrl?: string | null; listingUrl?: string | null; description?: string | null; locations?: Array<{ text?: string | null; }> | null; } /** * Minimum shape a detail record must satisfy for validation. */ interface ValidatableJobDetail extends ValidatableJobListing { /** Some runtime types expose this as a pre-computed number. */ descriptionLength?: number; } /** * A validation issue describing which required fields are missing. */ interface JobValidationIssue { /** The externalId of the job (or "(unknown)" if missing). */ externalId: string; /** List of field names that failed validation. */ missingFields: string[]; } /** * Result of a full validation pass across a set of listings and/or details. */ interface ValidationSummary { /** Whether all items passed validation. */ valid: boolean; /** Total number of items validated. */ total: number; /** Number of items that passed. */ passed: number; /** Number of items that failed. */ failed: number; /** Individual issues for each failed item. */ issues: JobValidationIssue[]; } /** * Check whether a string is a syntactically valid URL. */ declare function isValidUrl(url: string): boolean; /** * Validate a single listing for the minimum required fields. * * **Always required:** `externalId`, `applyUrl`, `listingUrl`. * * When the scraper is a **full** scraper (`isFull = true`), listings carry * full detail data, so additionally required: `title`, `description`, and * at least one location with non-empty text. * * @param listing - The listing to validate. * @param isFull - Whether this is from a "full" scraper (listing = detail). * @returns `null` if the listing is valid, or a {@link JobValidationIssue}. */ declare function validateListing(listing: ValidatableJobListing, isFull: boolean): JobValidationIssue | null; /** * Validate a single detail record for the minimum required fields. * * Required: `title`, `description`, `applyUrl`, `listingUrl`, and at least * one location with non-empty text. * * @param detail - The detail record to validate. * @returns `null` if valid, or a {@link JobValidationIssue}. */ declare function validateDetail(detail: ValidatableJobDetail): JobValidationIssue | null; /** * Validate an array of listings at once and return a summary. * * @param listings - The listings to validate. * @param isFull - Whether these are from a "full" scraper. * @returns A {@link ValidationSummary} with aggregate counts and per-item issues. */ declare function validateListings(listings: ValidatableJobListing[], isFull: boolean): ValidationSummary; /** * Validate an array of detail records at once and return a summary. * * @param details - The detail records to validate. * @returns A {@link ValidationSummary} with aggregate counts and per-item issues. */ declare function validateDetails(details: ValidatableJobDetail[]): ValidationSummary; export { type JobValidationIssue, type ValidatableJobDetail, type ValidatableJobListing, type ValidationSummary, isValidUrl, validateDetail, validateDetails, validateListing, validateListings };