diff --git a/src/index.ts b/src/index.ts index 18271a8..72f06ad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,10 @@ export { useSchemaBuilderConfig, } from "./i18n/schema-builder-config.tsx"; export type { Translation } from "./i18n/translation-keys.ts"; +export { + createSchemaFromJson, + inferSchema, +} from "./lib/schema-inference.ts"; export type { SchemaBuilderComponents, SchemaBuilderRegistry, @@ -45,6 +49,11 @@ export { useSlotProps, } from "./registry/index.ts"; export type { JsonSchema } from "./types/jsonSchema.ts"; +export { + type ValidationError, + type ValidationResult, + validateJson, +} from "./utils/jsonValidator.ts"; export { InferSchemaDialog, type InferSchemaDialogProps, diff --git a/src/lib/schema-inference.ts b/src/lib/schema-inference.ts index da7e408..0fcd04c 100644 --- a/src/lib/schema-inference.ts +++ b/src/lib/schema-inference.ts @@ -320,8 +320,16 @@ function inferNumberSchema(num: number): JsonSchema { // --- Main Inference Function --- /** - * Infers a JSON Schema from a JSON object - * Based on json-schema-generator approach + * Infers a JSON Schema fragment describing a single parsed JSON value. + * + * Recurses through objects and arrays, detecting primitive types, string + * formats (date, date-time, email, uuid, uri), enums and a few semantic + * formats across array items. The result is a bare schema fragment, not a + * full document — use {@link createSchemaFromJson} for a self-contained schema. + * + * @param obj - An already-parsed JSON value (object, array, or primitive). + * @returns The inferred JSON Schema fragment for that value. + * @public */ export function inferSchema(obj: unknown): JsonSchema { if (obj === null) return { type: "null" }; @@ -346,7 +354,16 @@ export function inferSchema(obj: unknown): JsonSchema { } /** - * Creates a full JSON Schema document from a JSON object + * Builds a complete, self-contained JSON Schema document from an example value. + * + * Wraps {@link inferSchema} and adds document-level fields (`$schema`, `title`, + * `description`). The root is always normalized to an `object` schema: object + * and array inputs are described directly, while a primitive root is wrapped + * under a `value` property. + * + * @param jsonObject - An already-parsed JSON value to derive the schema from. + * @returns A draft-07 JSON Schema document describing the input. + * @public */ export function createSchemaFromJson(jsonObject: unknown): JsonSchema { const inferredSchema = inferSchema(jsonObject); diff --git a/src/utils/jsonValidator.ts b/src/utils/jsonValidator.ts index 7c7b593..5919aa3 100644 --- a/src/utils/jsonValidator.ts +++ b/src/utils/jsonValidator.ts @@ -11,15 +11,35 @@ const ajv = new Ajv({ }); addFormats(ajv); +/** + * A single validation problem found in the input. + * @public + */ export interface ValidationError { + /** + * JSON Pointer (RFC 6901) to the offending value, e.g. `/user/age`. + * `"/"` denotes the document root (used for syntax errors and empty input). + */ path: string; + /** Human-readable description of the problem (from ajv, or a parse error). */ message: string; + /** 1-based line number of the error in the source text, when locatable. */ line?: number; + /** 1-based column number of the error in the source text, when locatable. */ column?: number; } +/** + * Outcome of validating a JSON document against a schema. + * @public + */ export interface ValidationResult { + /** `true` when the input parses and satisfies the schema. */ valid: boolean; + /** + * The problems found. Empty (or omitted) when {@link ValidationResult.valid} + * is `true`; otherwise contains one entry per violation. + */ errors?: ValidationError[]; } @@ -149,7 +169,18 @@ export function extractErrorPosition( } /** - * Validates a JSON string against a schema and returns validation results + * Validates a JSON document against a JSON Schema. + * + * Never throws: malformed JSON, empty input, and schema violations are all + * reported through the returned {@link ValidationResult}. Schema-level errors + * carry a JSON Pointer `path`; syntax/parse errors are reported at the root + * (`"/"`) with `line`/`column` pointing at the offending position when known. + * + * @param jsonInput - The JSON document to validate, as a raw string. + * @param schema - The JSON Schema to validate against. + * @returns A {@link ValidationResult}; `valid` is `true` only when the input + * parses and satisfies the schema, otherwise `errors` lists each problem. + * @public */ export function validateJson( jsonInput: string,