Files
accounted/lib/ai/validation-helpers.ts
T
Jakob Wennberg 3f255ea201 refactor: consolidate AI analyzers into shared lib/ai module and add journal entry reversal columns
Extract shared vision/document analysis logic into lib/ai (vision-client, document-analyzer,
image preprocessing, validation helpers), simplifying invoice-analyzer, receipt-analyzer, and
document classifier. Add migration 046 for journal entry reversal/correction link columns
(reversed_by_id, reverses_id, correction_of_id) required by storno service. Update extension
components and shared UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 17:14:44 +01:00

118 lines
2.9 KiB
TypeScript

/**
* Validation Helpers for AI Extraction Results
*
* Shared validation functions used by receipt-analyzer and invoice-analyzer
* to sanitize and validate AI-extracted field values.
*/
/**
* Validate and trim a string value.
* Returns null for empty/non-string values.
*/
export function validateString(value: unknown): string | null {
if (typeof value === 'string' && value.trim()) {
return value.trim()
}
return null
}
/**
* Validate a numeric value.
* Handles both number and string inputs, stripping non-numeric characters.
* Returns null for invalid values.
*/
export function validateNumber(value: unknown): number | null {
if (typeof value === 'number' && !isNaN(value)) {
return value
}
if (typeof value === 'string') {
const parsed = parseFloat(value.replace(/[^\d.-]/g, ''))
if (!isNaN(parsed)) {
return parsed
}
}
return null
}
/**
* Validate and normalize a date to ISO format (YYYY-MM-DD).
* Returns null for invalid dates.
*/
export function validateDate(value: unknown): string | null {
if (typeof value !== 'string') return null
const date = new Date(value)
if (isNaN(date.getTime())) return null
return date.toISOString().split('T')[0]
}
/**
* Validate and normalize a time value to HH:MM format.
* Returns null for invalid times.
*/
export function validateTime(value: unknown): string | null {
if (typeof value !== 'string') return null
// Match HH:MM or HH:MM:SS
const match = value.match(/^(\d{2}):(\d{2})(:\d{2})?$/)
if (match) {
return `${match[1]}:${match[2]}`
}
return null
}
/**
* Validate and normalize a Swedish org number (XXXXXX-XXXX).
* Swedish org numbers are 10 digits.
* Returns null for invalid values.
*/
export function validateOrgNumber(value: unknown): string | null {
if (typeof value !== 'string') return null
const digits = value.replace(/\D/g, '')
// Swedish org numbers are 10 digits
if (digits.length === 10) {
return `${digits.slice(0, 6)}-${digits.slice(6)}`
}
return null
}
/**
* Validate a Swedish VAT number (SE prefix, at least 12 chars).
* Returns null for invalid values.
*/
export function validateVatNumber(value: unknown): string | null {
if (typeof value !== 'string') return null
const cleaned = value.trim().toUpperCase()
if (cleaned.startsWith('SE') && cleaned.length >= 12) {
return cleaned
}
return null
}
/**
* Check if an org number is in Swedish format (10 digits).
*/
export function isSwedishOrgNumber(value: string): boolean {
const digits = value.replace(/\D/g, '')
return digits.length === 10
}
/**
* Validate a 4-digit BAS account number (1000-9999).
* Returns null for invalid values.
*/
export function validateAccountNumber(value: string | undefined | null): string | null {
if (!value) return null
const digits = value.replace(/\D/g, '')
if (digits.length === 4 && parseInt(digits) >= 1000 && parseInt(digits) <= 9999) {
return digits
}
return null
}