import type { Schema } from '../base.ts'; import { createIssue, failure, success, createParseMethods, SCHEMA_KIND } from '../base.ts'; import { optional } from '../utils/optional.ts'; import { nullable } from '../utils/nullable.ts'; const parseMethods = createParseMethods(); /** * Schema for validating string values. * * @example * ```typescript * const schema = s.string(); * const name = schema.parse('John'); // "John" * schema.parse(123); // throws ValidationError * ``` */ export class StringSchema implements Schema { readonly [SCHEMA_KIND] = 'StringSchema'; description?: string; private _min?: number; private _max?: number; private _email?: boolean; private _url?: boolean; readonly '~standard' = { version: 1 as const, vendor: 'agentuity', validate: (value: unknown) => { if (typeof value !== 'string') { return failure([createIssue(`Expected string, got ${typeof value}`)]); } if (this._min !== undefined && value.length < this._min) { return failure([ createIssue(`String must be at least ${this._min} characters, got ${value.length}`), ]); } if (this._max !== undefined && value.length > this._max) { return failure([ createIssue(`String must be at most ${this._max} characters, got ${value.length}`), ]); } if (this._email) { // Basic email regex - matches most valid emails const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(value)) { return failure([createIssue(`Invalid email format`)]); } } if (this._url) { try { new URL(value); } catch { return failure([createIssue(`Invalid URL format`)]); } } return success(value); }, types: undefined as unknown as { input: string; output: string }, }; describe(description: string): this { this.description = description; return this; } /** * Set minimum length. * * @example * ```typescript * const schema = s.string().min(3); * schema.parse('hello'); // "hello" * schema.parse('hi'); // throws ValidationError * ``` */ min(length: number): StringSchema { const clone = this._clone(); clone._min = length; return clone; } /** * Set maximum length. * * @example * ```typescript * const schema = s.string().max(10); * schema.parse('hello'); // "hello" * schema.parse('hello world'); // throws ValidationError * ``` */ max(length: number): StringSchema { const clone = this._clone(); clone._max = length; return clone; } /** * Validate email format. * * @example * ```typescript * const schema = s.string().email(); * schema.parse('user@example.com'); // "user@example.com" * schema.parse('invalid'); // throws ValidationError * ``` */ email(): StringSchema { const clone = this._clone(); clone._email = true; return clone; } /** * Validate URL format. * * @example * ```typescript * const schema = s.string().url(); * schema.parse('https://example.com'); // "https://example.com" * schema.parse('invalid'); // throws ValidationError * ``` */ url(): StringSchema { const clone = this._clone(); clone._url = true; return clone; } optional() { return optional(this); } nullable() { return nullable(this); } private _clone(): StringSchema { const clone = new StringSchema(); clone.description = this.description; clone._min = this._min; clone._max = this._max; clone._email = this._email; clone._url = this._url; return clone; } parse = parseMethods.parse; safeParse = parseMethods.safeParse; } /** * Create a string schema. * * @example * ```typescript * const nameSchema = s.string().describe('User name'); * const name = nameSchema.parse('John'); * ``` */ export function string(): StringSchema { return new StringSchema(); }