### Install Sury Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Install the Sury library using npm. ```APIDOC ## Install Sury ### Description Installs the Sury library via npm. ### Method `npm install sury` ### Note No additional installation of the ReScript compiler is required for the library to function. ``` -------------------------------- ### Install Sury using npm Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Installs the Sury library using npm. No external compiler like ReScript is required for the library to function. ```sh npm install sury ``` -------------------------------- ### xsAI: Generate Structured Data with Sury Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage An example demonstrating how to use Sury's schema definition with the `xsAI` library to generate structured data based on AI prompts and a defined schema. ```typescript import { generateObject } from "@xsai/generate-object"; import { env } from "node:process"; import * as S from "sury"; const { object } = await generateObject({ apiKey: env.OPENAI_API_KEY!, baseURL: "https://api.openai.com/v1/", messages: [ { content: "Extract the event information.", role: "system", }, { content: "Alice and Bob are going to a science fair on Friday.", role: "user", }, ], model: "gpt-4o", schema: S.schema({ name: S.string, date: S.string, participants: S.array(S.string), }), }); ``` -------------------------------- ### Sury: Reverse Serialization Example Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how Sury can serialize data back to its initial format, which is useful for complex schemas with transformations. It takes a data object and a schema definition to perform the reverse conversion. ```typescript S.reverseConvertOrThrow({ username: "billie", xp: 100 }, Player); // => returns { username: "billie", xp: 100 } ``` -------------------------------- ### Coerce String to Number Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates the use of `S.to` for coercing data types. This example shows how to create a schema that expects a string but converts it to a number. It also illustrates that `S.reverseConvertOrThrow` correctly converts a number back to its string representation. ```typescript const schema = S.string.with(S.to, S.number); S.parseOrThrow("123", schema); //? 123. S.parseOrThrow("abc", schema); //? throws: Failed parsing: Expected number, received "abc" // Reverse works correctly as well 🔥 S.reverseConvertOrThrow(123, schema); //? "123" ``` -------------------------------- ### Strict Object Schema in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to use `S.strict` to create an object schema that rejects inputs with unrecognized keys. An example shows parsing an object with an extra key, resulting in an error. ```typescript const personSchema = S.strict( S.schema({ name: S.string, }) ); S.parseOrThrow( { name: "bob dylan", extraKey: 61, }, personSchema ); // => throws S.Error ``` -------------------------------- ### Transform Integer to String Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Defines a transformation schema to convert an integer to its string representation and vice-versa. It handles parsing integers from strings and includes error handling for invalid input. This is an example, and `S.int32.with(S.to, S.string)` is a more optimized alternative. ```typescript const intToString = (schema) => S.transform( schema, (int) => int.toString(), (string, s) => { const int = parseInt(string, 10); if (isNaN(int)) { s.fail("Can't convert string to int"); } return int; } ); ``` -------------------------------- ### Reverse Object Schema with Field Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows the reversal of a more complex object schema that includes a string field. This example highlights how `S.reverse` can transform an object schema into a schema that expects the object's field value, converting it back into the original object structure upon parsing. ```typescript const schema = S.object((s) => s.field("foo", S.string)); S.parseOrThrow({ foo: "bar" }, schema); // "bar" const reversed = S.reverse(schema); S.parseOrThrow("bar", reversed); // {"foo": "bar"} S.parseOrThrow(123, reversed); // throws S.error with the message: `Failed parsing: Expected string, received 123` ``` -------------------------------- ### ISO Datetime Parsing and Validation with Sury (TypeScript) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates the usage of `S.datetime(S.string)` for validating ISO 8601 formatted datetime strings in UTC. It shows examples of valid and invalid inputs, and highlights that the schema transforms the string input into a `Date` object. ```typescript const datetimeSchema = S.datetime(S.string); // The datetimeSchema has the type S.Schema // String is transformed to the Date instance S.parseOrThrow("2020-01-01T00:00:00Z", datetimeSchema); // pass S.parseOrThrow("2020-01-01T00:00:00.123Z", datetimeSchema); // pass S.parseOrThrow("2020-01-01T00:00:00.123456Z", datetimeSchema); // pass (arbitrary precision) S.parseOrThrow("2020-01-01T00:00:00+02:00", datetimeSchema); // fail (no offsets allowed) ``` -------------------------------- ### Shape Schema for Circle Object Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates using `S.shape` to transform a number into a structured object representing a circle. This is useful for reshaping data statically. The example shows both parsing and reverse conversion, highlighting `S.shape`'s ability to handle data transformation in both directions. ```typescript const circleSchema = S.number.with(S.shape, (radius) => ({ kind: "circle", radius: radius, })); S.parseOrThrow(1, circleSchema); //? { kind: "circle", radius: 1 } // Also works in reverse 🔄 S.reverseConvertOrThrow({ kind: "circle", radius: 1 }, circleSchema); //? 1 ``` -------------------------------- ### Parsing Data with Sury Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to parse and validate data using Sury schemas, including error handling. ```APIDOC ## Parsing Data ### Description Parses unknown data against a defined schema. Returns a validated and type-safe deep clone if successful. Throws an error if the data is invalid. ### Methods - `S.parseOrThrow(data, schema)` - `S.safe(() => ...)` - `S.safeAsync(() => ...)` - `S.parseAsyncOrThrow(data, schema)` ### Parameters - **data** (any) - The data to parse. - **schema** (S.Schema) - The schema to validate against. ### Request Example (parseOrThrow) ```ts import * as S from "sury"; const Player = S.schema({ username: S.string, xp: S.number, }); // Valid data const validPlayer = S.parseOrThrow({ username: "billie", xp: 100 }, Player); // => returns { username: "billie", xp: 100 } // Invalid data try { S.parseOrThrow({ username: "billie", xp: "not a number" }, Player); } catch (e) { // e is an S.Error console.error(e.message); // "Failed parsing at ["xp"]: Expected number, got string" } ``` ### Request Example (safe) ```ts const result = S.safe(() => S.parseOrThrow({ username: "billie", xp: "not a number" }, Player) ); if (!result.success) { result.error; // handle error } else { result.data; // do stuff } ``` ### Response #### Success Response (200) - **data** (T) - A strongly-typed, deep clone of the input data if validation succeeds. #### Error Response - **error** (S.Error) - An error object detailing the validation failure if `parseOrThrow` is used within `safe` or `safeAsync` and the data is invalid. ``` -------------------------------- ### Sury: Advanced Schema Creation and Usage Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates the creation of an advanced Sury schema with transformations using `S.to`, `S.shape`, and `S.meta`. It shows how to parse input data to output format and reverse the schema for parsing output to input format. ```typescript // 1. Create some advanced schema with transformations // S.to - for easy & fast coercion // S.shape - for fields transformation // S.meta - with examples in Output format const User = S.schema({ USER_ID: S.string.with(S.to, S.bigint), USER_NAME: S.string, }) .with(S.shape, (input) => ({ id: input.USER_ID, name: input.USER_NAME, })) .with(S.meta, { description: "User entity in our system", examples: [ { id: 0n, name: "Dmitry", }, ], }); // On hover: // S.Schema<{ // id: bigint; // name: string; // }, { // USER_ID: string; // USER_NAME: string; // }> // 2. You can use it for parsing Input to Output S.parseOrThrow( { USER_ID: "0", USER_NAME: "Dmitry", }, userSchema ); // { id: 0n, name: "Dmitry" } // See how "0" is turned into 0n and fields are renamed // 3. And reverse the schema and use it for parsing Output to Input S.parseOrThrow( { id: 0n, name: "Dmitry", }, S.reverse(userSchema) ); // { USER_ID: "0", USER_NAME: "Dmitry" } // Just use `S.reverse` and get a full-featured schema with switched `Output` and `Input` types // Note: You can use `S.reverseConvertOrThrow(data, schema)` if you don't need to perform validation ``` -------------------------------- ### Type Inference Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to infer static types from Sury schemas. ```APIDOC ## Inferred Types ### Description Sury automatically infers static TypeScript types from schema definitions. These can be extracted using utility types. ### Utility Types - `S.Infer`: Infers the general type of the schema. - `S.Output`: Infers the type of the data after parsing/validation. - `S.Input`: Infers the type of the data expected as input. ### Request Example ```ts import * as S from "sury"; const Player = S.schema({ username: S.string, xp: S.number, }); //? S.Schema<{ username: string; xp: number }, { username: string; xp: number }> type PlayerType = S.Infer; // Use the inferred type in your code const player: PlayerType = { username: "billie", xp: 100 }; ``` ### Response #### Success Response (Type Inference) - **PlayerType** (type) - A TypeScript type alias representing the structure defined by the `Player` schema. ``` -------------------------------- ### Define Nullable String Schema in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to create a nullable string schema using `S.nullable` and parse values. Null inputs are converted to undefined. ```typescript const nullableStringSchema = S.nullable(S.string); S.parseOrThrow("asdf", nullableStringSchema); // => "asdf" S.parseOrThrow(null, nullableStringSchema); // => undefined ``` -------------------------------- ### Compile Custom Async Assert Operation Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates compiling a custom asynchronous assert operation using `S.compile`. This allows for fine-tuned control over input and output types, and asynchronous execution. It accepts `unknown` as input and returns a `Promise` after assertion. ```typescript const operation = S.compile(S.string, "Any", "Assert", "Async"); typeof operation; // => (input: unknown) => Promise await operation("Hello world!"); // () ``` -------------------------------- ### Define Nullish String Schema in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to create a nullish string schema using `S.nullish`, which accepts both null and undefined inputs. Parsed null values remain null, and undefined values become undefined. ```typescript const nullishStringSchema = S.nullish(S.string); S.parseOrThrow("asdf", nullishStringSchema); // => "asdf" S.parseOrThrow(null, nullishStringSchema); // => null S.parseOrThrow(undefined, nullishStringSchema); // => undefined ``` -------------------------------- ### Basic Schema Definition Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Defines a basic schema for a player object with username and xp properties. ```APIDOC ## Basic Schema Definition ### Description Defines a schema for a 'Player' object, specifying 'username' as a string and 'xp' as a number. ### Method `S.schema({...})` ### Endpoint N/A (Library Function) ### Parameters #### Request Body - **username** (string) - Required - The player's username. - **xp** (number) - Required - The player's experience points. ### Request Example ```ts import * as S from "sury"; const Player = S.schema({ username: S.string, xp: S.number, }); ``` ### Response #### Success Response (Schema Definition) - **Player** (S.Schema) - The defined schema object. ``` -------------------------------- ### Reverse Nullable String Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates reversing a nullable string schema using `S.reverse`. The reversed schema effectively becomes an optional string schema, demonstrating how `S.reverse` can invert schema definitions. ```typescript S.reverse(S.nullable(S.string)); // S.optional(S.string) ``` -------------------------------- ### Global Strictness Setting in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to configure the default behavior for handling unknown keys across all schemas in an application using `S.global({ defaultAdditionalItems: 'strict' })`. ```typescript S.global({ defaultAdditionalItems: "strict", }); ``` -------------------------------- ### Define Basic Array Schema in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows the basic syntax for defining an array schema where all elements must be strings using `S.array(S.string)`. ```typescript const stringArraySchema = S.array(S.string); ``` -------------------------------- ### Array Schema Refinements in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates how to apply length-based refinements to array schemas: `S.max` for maximum length, `S.min` for minimum length, and `S.length` for an exact length. ```typescript S.max(S.array(S.string), 5); // Array must be 5 or fewer items long S.min(S.array(S.string) 5); // Array must be 5 or more items long S.length(S.array(S.string) 5); // Array must be exactly 5 items long ``` -------------------------------- ### Convert Schema to Expression String Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates converting a schema into its string expression representation using `S.toExpression`. This is useful for debugging and understanding the schema's structure. It can also convert a schema with an assigned name directly to that name. ```typescript S.toExpression(S.schema({ abc: 123 })); // "{ abc: 123; }" S.toExpression(S.name(S.string, "Address")); // "Address" ``` -------------------------------- ### Create Custom Schema with S.instance and S.transform Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Define custom schemas for any TypeScript type by choosing a base schema (like S.instance) and using S.transform to add custom parsing and serialization logic. S.meta can optionally customize the schema's name and add metadata. ```typescript const mySet = (itemSchema: S.Schema): S.Schema> => S.instance(Set) .with(S.transform, (input) => { const output = new Set(); input.forEach((item) => { output.add(S.parseOrThrow(item, itemSchema)); }); return output; }) .with(S.meta, { name: `Set<${S.toExpression(itemSchema)}>`, // Note: toExpression might need proper implementation or context }); const numberSetSchema = mySet(S.number); type NumberSet = S.Infer; // Set S.parseOrThrow(new Set([1, 2, 3]), numberSetSchema); // passes S.parseOrThrow(new Set([1, 2, "3"]), numberSetSchema); // throws S.Error: Failed parsing: Expected number, received "3" S.parseOrThrow([1, 2, 3], numberSetSchema); // throws S.Error: Failed parsing: Expected Set, received [1, 2, 3] ``` -------------------------------- ### Safe Error Handling with ReScript Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Utility functions `S.safe` and `S.safeAsync` provide a convenient way to handle potential errors thrown by schema operations. These functions catch exceptions and wrap the result in a `Result` type, simplifying error management. ```typescript const result = S.safe(() => S.parseOrThrow(123, S.string)); ``` -------------------------------- ### Configure Global Strict Object Parsing Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates how to globally configure `Sury`'s behavior for handling unknown keys in object parsing. By setting `defaultAdditionalItems` to 'strict', the library will throw an error if unexpected keys are present in the parsed object. ```rescript S.global({ defaultAdditionalItems: "strict", }) ``` -------------------------------- ### Advanced Object Schema with Field Renaming and Transformation in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates creating an object schema that renames input fields and transforms them during parsing using a function passed to `S.object`. It also shows how to infer the output type and reverse the conversion. ```typescript const userSchema = S.object((s) => ({ id: s.field("USER_ID", S.number), name: s.field("USER_NAME", S.string), })); S.parseOrThrow( { USER_ID: 1, USER_NAME: "John", }, userSchema ); // => returns { id: 1, name: "John" } // Infer output TypeScript type of the userSchema type User = S.Infer; // { id: number; name: string } S.reverseConvertOrThrow( { id: 1, name: "John", }, userSchema ); // => returns { USER_ID: 1, USER_NAME: "John" } ``` -------------------------------- ### Sury: Schema to JSON Schema Conversion Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to log Sury's internal schema representation, which is similar to JSON Schema. It also shows how to explicitly convert a Sury schema to the official JSON Schema specification for interoperability. ```typescript console.log( S.schema("Hello world!").with(S.meta, { description: "Your greeting :)" }) ); // { // type: "string", // const: "Hello world!", // description: "Your greeting :)", // ...a few internal properties // } // See how all the properties and examples are in the Input format. It's just asking to put itself to Fastify or any other server with OpenAPI integration 😁 ``` ```typescript S.toJSONSchema(User); // { // type: "object", // additionalProperties: true, // properties: { // USER_ID: { // type: "string", // }, // USER_NAME: { // type: "string", // }, // }, // required: ["USER_ID", "USER_NAME"], // description: "User entity in our system", // examples: [ // { // USER_ID: "0", // USER_NAME: "Dmitry", // }, // ], // } ``` -------------------------------- ### Converting Values with ReScript Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Operations for converting input values to the schema's output type without strict type validation. This is useful for direct transformations where input type checking is not required. Note that refinements and transforms within the schema will still be applied. ```typescript S.convertOrThrow(Input, Schema) => Output S.convertToJsonOrThrow(Input, Schema) => Json S.convertToJsonStringOrThrow(Input, Schema) => string ``` -------------------------------- ### Add Metadata to Schema with S.meta Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Use S.meta to attach descriptive metadata to a schema. This metadata can be used to document fields or aid in JSON schema generation. It does not affect runtime behavior. ```typescript const documentedStringSchema = S.string.with(S.meta, { description: "A useful bit of text, if you know what to do with it.", }); documentedStringSchema.description; // A useful bit of text… S.toJSONSchema(documentedStringSchema); // { // "type": "string", // "description": "A useful bit of text, if you know what to do with it." // } ``` -------------------------------- ### Implement Asynchronous Refinements with S.asyncParserRefine Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Implement asynchronous validation logic for parsers using S.asyncParserRefine. This is useful for operations like checking external resources, such as verifying if a user ID corresponds to an active user. Use `parseAsync` for processing. ```typescript const userSchema = S.schema({ id: S.string.with(S.uuid).with(S.asyncParserRefine, async (id, s) => { // Assuming checkIsActiveUser is an async function that returns boolean const isActiveUser = await checkIsActiveUser(id); if (!isActiveUser) { s.fail(`The user ${id} is inactive.`); } }), name: S.string, }); type User = S.Infer; // { id: string, name: string } // Example usage: // await S.parseAsyncOrThrow( // { // id: "some-uuid-string", // name: "John" // }, // userSchema // ); ``` -------------------------------- ### Number Refinements in Sury (TypeScript) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Explains how to apply numeric constraints in Sury using `S.max` and `S.min` to define upper and lower bounds for number schemas. Custom error messages can be specified as a third argument. ```typescript S.max(S.number, 5); // Number must be lower than or equal to 5 S.min(S.number, 5); // Number must be greater than or equal to 5 S.max(S.number, 5, "this👏is👏too👏big"); ``` -------------------------------- ### Assign Name to Schema Metadata Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to assign a name to a schema using `S.name` in conjunction with `S.meta`. This name is used internally to generate more readable error messages, aiding in debugging. ```typescript const schema = S.schema({ abc: 123 }.with(S.meta, { name: "Abc" })); schema.name; // "Abc" ``` -------------------------------- ### Infer static types from Sury schemas Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates how Sury automatically infers static TypeScript types from schema definitions. Types like 'Infer', 'Output', and 'Input' can be used to extract these types for use in your code. ```ts const Player = S.schema({ username: S.string, xp: S.number, }); //? S.Schema<{ username: string; xp: number }, { username: string; xp: number }> type Player = S.Infer; // Use it in your code const player: Player = { username: "billie", xp: 100 }; ``` -------------------------------- ### Optional Schemas and Default Values in Sury (TypeScript) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to make any Sury schema optional using `S.optional`. It covers providing a default value directly, using a function for dynamic defaults, and the processing order for default values. ```typescript const schema = S.optional(S.string); S.parseOrThrow(undefined, schema); // => returns undefined type A = S.Infer; // string | undefined const stringWithDefaultSchema = S.optional(S.string, "tuna"); S.parseOrThrow(undefined, stringWithDefaultSchema); // => returns "tuna" type A = S.Infer; // string const numberWithRandomDefault = S.optional(S.number, Math.random); S.parseOrThrow(undefined, numberWithRandomDefault); // => 0.4413456736055323 S.parseOrThrow(undefined, numberWithRandomDefault); // => 0.1871840107401901 S.parseOrThrow(undefined, numberWithRandomDefault); // => 0.7223408162401552 // Sury processes default values as follows: // 1. If the input is `undefined`, the default value is returned. // 2. Otherwise, the data is parsed using the base schema. ``` -------------------------------- ### Enabling and Using Advanced Sury Schemas (TypeScript) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to explicitly enable advanced schemas like JSON and JSON string validation in Sury. It details how to use `S.json`, `S.jsonString`, and apply transformations using `.with(S.to, ...)` for parsing and serialization. ```typescript S.enableJson(); S.enableJsonString(); // JSON type // Allows string | boolean | number | null | Record | JSON[] S.json; // JSON string // Asserts that the input is a valid JSON string S.jsonString; S.jsonStringWithSpace(2); // Parses JSON string and validates that it's a number // JSON string -> number S.jsonString.with(S.to, S.number); // Serializes number to JSON string // number -> JSON string S.number.with(S.to, S.jsonString); ``` -------------------------------- ### Merge Object Schemas in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to combine two object schemas using `S.merge` to create a new schema that includes fields from both. It notes that the function throws an error if schemas share keys and inherits the 'unknownKeys' policy from the second schema. ```typescript const baseTeacherSchema = S.schema({ students: S.array(S.string) }); const hasIDSchema = S.schema({ id: S.string }); const teacherSchema = S.merge(baseTeacherSchema, hasIDSchema); type Teacher = S.Infer; // => { students: string[], id: string } ``` -------------------------------- ### Define a basic object schema with Sury Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how to define a simple object schema named 'Player' using Sury. This schema specifies that the object should have a 'username' (string) and 'xp' (number). ```ts import * as S from "sury"; // 4.3 kB (min + gzip) const Player = S.schema({ username: S.string, xp: S.number, }); ``` -------------------------------- ### Reset Object Schema to Default Stripping Behavior in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Explains the use of `S.strip` to revert an object schema to its default behavior, which is stripping unrecognized keys during parsing. ```typescript Use the `S.strip` function to reset an object schema to the default behavior (stripping unrecognized keys). ``` -------------------------------- ### Safe Asynchronous Error Catching Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates the asynchronous version, `S.safeAsync`, for catching errors in asynchronous parsing operations. This allows for robust error handling within async functions, ensuring that errors are caught and managed functionally. ```typescript const result = await S.safeAsync(async () => { const passed = await S.parseAsyncOrThrow(data, S.schema(S.boolean)); return passed ? 1 : 0; }); ``` -------------------------------- ### Defining Primitive and Literal Schemas in Sury (TypeScript) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates the definition of primitive data types (string, number, boolean, etc.) and literal values (string, number, boolean, null, undefined, Symbol, NaN) using the Sury library. It also shows the catch-all 'unknown'/'any' and the 'never' type. ```typescript import * as S from "sury"; // Primitive values S.string; S.number; S.int32; S.boolean; S.bigint; S.symbol; S.void; // Literal values // Supports any JS type // Validated using strict equal checks S.schema("tuna"); S.schema(12); S.schema(2n); S.schema(true); S.schema(undefined); S.schema(null); S.schema(Symbol("terrific")); // NaN literals // Validated using Number.isNaN S.schema(NaN); // Catch-all type // Allows any value S.unknown; S.any; // Never type // Allows no values S.never; ``` -------------------------------- ### Define Basic Object Schema with Inferred Type in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Illustrates the creation of a basic object schema for a 'Dog' with required 'name' (string) and 'age' (number) properties. The `S.Infer` utility is used to derive the TypeScript type. ```typescript // all properties are required by default const dogSchema = S.schema({ name: S.string, age: S.number, }); // extract the inferred type like this type Dog = S.Infer; // equivalent to: type Dog = { name: string; age: number; }; ``` -------------------------------- ### Parsing Values with ReScript Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Operations for parsing and validating input values against a schema, transforming them to the expected output type. These include parsing any value, JSON, JSON strings, and asynchronous parsing. ```typescript S.parseOrThrow(unknown, Schema) => Output S.parseJsonOrThrow(Json, Schema) => Output S.parseJsonStringOrThrow(string, Schema) => Output S.parseAsyncOrThrow(unknown, Schema) => Promise ``` -------------------------------- ### Sury: Compiled ParseOrThrow Performance Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows the compiled JavaScript code for Sury's `S.parseOrThrow` function, illustrating its performance optimization for data validation and transformation. ```javascript // This is how S.parseOrThrow(data, userSchema) is compiled (i) => { if (typeof i !== "object" || !i) { e[3](i); } let v0 = i["USER_ID"], v2 = i["USER_NAME"]; if (typeof v0 !== "string") { e[0](v0); } let v1; try { v1 = BigInt(v0); } catch (_) { e[1](v0); } if (typeof v2 !== "string") { e[2](v2); } return { id: v1, name: v2 }; }; ``` -------------------------------- ### Deep Strict and Deep Strip Object Schemas in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Explains `S.deepStrict` and `S.deepStrip` for applying strictness or stripping behavior to all nested schemas within an object schema, unlike `S.strict` and `S.strip` which only affect the top level. ```typescript const schema = S.schema({ bar: { baz: S.string, }, }); S.strict(schema); // { "baz": string } will still allow unknown keys S.deepStrict(schema); // { "baz": string } will not allow unknown keys ``` -------------------------------- ### Asserting Data Validity with ReScript Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage The `S.assertOrThrow` operation allows for asserting that an input value conforms to a schema without returning a value. This is typically faster than `parseOrThrow` as it avoids the overhead of returning the parsed data. ```typescript S.assertOrThrow(data: unknown, Schema) asserts data is Input ``` -------------------------------- ### Safe Synchronous Error Catching Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to use `S.safe` to catch synchronous errors thrown by parsing operations. It returns a result object with either a `success` property containing the value or an `error` property containing the caught error. ```typescript const result = S.safe(() => S.parseOrThrow(true, S.schema(false))); if (result.success) { console.log(result.value); } else { console.log(result.error); } ``` -------------------------------- ### Reversing Schema Operations with ReScript Schema Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Functions to perform operations in the reverse direction of the schema, converting schema values back to their initial input format. This is analogous to serializing or decoding data. ```typescript S.reverseConvertOrThrow(Output, Schema) => Input S.reverseConvertToJsonOrThrow(Output, Schema) => Json S.reverseConvertToJsonStringOrThrow(Output, Schema) => string S.reverseConvertAsyncOrThrow(Output, Schema) => Promise ``` -------------------------------- ### Implement Unions with S.union in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage S.union creates a schema that accepts any of the provided sub-schemas, representing a logical OR. It's effective for handling data that can conform to multiple types or structures. ```typescript // TypeScript type for reference: // type Union = string | number; const stringOrNumberSchema = S.union([S.string, S.number]); S.parseOrThrow("foo", stringOrNumberSchema); // passes S.parseOrThrow(14, stringOrNumberSchema); // passes ``` -------------------------------- ### Define Object Schema with Literal Fields in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates defining an object schema where fields can be literal JavaScript values (strings, numbers, objects). This allows for stricter type checking on specific values. ```typescript const meSchema = S.schema({ id: S.number, name: "Dmitry Zakharov", age: 23, kind: "human", metadata: { description: "What?? Even an object with NaN works! Yes 🔥", money: NaN, }, }); ``` -------------------------------- ### Reverse Conversion Operations Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage These operations perform the reverse of conversion, transforming schema output values back to their initial input format. ```APIDOC ## Reverse Conversion Operations ### Description Converts schema output values back to their initial input format (serializing or decoding). ### Operations - **S.reverseConvertOrThrow** - Interface: `(Output, Schema) => Input` - Description: Converts schema value to the output type. - **S.reverseConvertToJsonOrThrow** - Interface: `(Output, Schema) => Json` - Description: Converts schema value to JSON. - **S.reverseConvertToJsonStringOrThrow** - Interface: `(Output, Schema) => string` - Description: Converts schema value to JSON string. - **S.reverseConvertAsyncOrThrow** - Interface: `(Output, Schema) => promise` - Description: Converts schema value to the output type having async transformations. ``` -------------------------------- ### Assertion Operation Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Asserts that an input value conforms to the schema without returning a value, making it faster for validation-only checks. ```APIDOC ## Assertion Operation ### Description Asserts that the input value is valid according to the schema. This operation is faster than parsing when only validation is needed as it does not return a value. ### Operation - **S.assertOrThrow** - Interface: `(data: unknown, Schema) asserts data is Input` - Description: Asserts that the input value is valid. Since the operation doesn't return a value, it's 2-3 times faster than `parseOrThrow` depending on the schema. ``` -------------------------------- ### Sury: JSON Schema to Sury Schema Conversion Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to convert an official JSON Schema into a Sury schema using `S.fromJSONSchema`. This allows for validation against custom JSON Schemas within the Sury framework. ```typescript S.assertOrThrow( "example.com", S.fromJSONSchema({ type: "string", format: "email", }) ); // Throws S.Error: Failed asserting: Invalid email address ``` -------------------------------- ### Parse data with Sury and handle errors Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to parse data using a defined Sury schema. 'parseOrThrow' validates and returns a typed clone, throwing an error on invalid data. 'safe' and 'safeAsync' provide a way to handle potential errors gracefully. ```ts S.parseOrThrow({ username: "billie", xp: 100 }, Player); // => returns { username: "billie", xp: 100 } S.parseOrThrow({ username: "billie", xp: "not a number" }, Player); // => throws S.Error: Failed parsing at ["xp"": Expected number, got string const result = S.safe(() => S.parseOrThrow({ username: "billie", xp: "not a number" }, Player) ); // Or for async operations: const result = await S.safeAsync(() => S.parseAsyncOrThrow({ username: "billie", xp: "not a number" }, Player) ); // The result type is a discriminated union, so you can handle both cases conveniently: if (!result.success) { result.error; // handle error } else { result.data; // do stuff } ``` -------------------------------- ### Sury: Compiled ReverseConvertOrThrow Performance Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Displays the compiled JavaScript code for Sury's `S.reverseConvertOrThrow` function, highlighting its efficiency in serializing data from output format to input format. ```javascript // This is how S.reverseConvertOrThrow(data, userSchema) is compiled (i) => { let v0 = i["id"]; return { USER_ID: "" + v0, USER_NAME: i["name"] }; }; ``` -------------------------------- ### Apply Custom Validation Logic with S.refine Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Add custom validation logic to schemas using S.refine. This is useful for checks not covered by the type system, such as validating string length or number properties. The refinement function is applied during both parsing and serialization. ```typescript const shortStringSchema = S.string.with(S.refine, (value, s) => { if (value.length > 255) { s.fail("String can't be more than 255 characters"); } }); ``` -------------------------------- ### Configure Global NaN Number Validation Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to disable NaN validation for number parsing globally. Setting `disableNanNumberValidation` to `true` can potentially improve performance when dealing with numbers that are guaranteed not to be NaN. ```rescript S.global({ disableNanNumberValidation: true, }) ``` -------------------------------- ### Parsing Operations Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage These operations validate and transform input values against a schema to the expected output type. ```APIDOC ## Parsing Operations ### Description Validates and transforms input values against a schema to the expected output type. ### Operations - **S.parseOrThrow** - Interface: `(unknown, Schema) => Output` - Description: Parses any value with the schema. - **S.parseJsonOrThrow** - Interface: `(Json, Schema) => Output` - Description: Parses JSON value with the schema. - **S.parseJsonStringOrThrow** - Interface: `(string, Schema) => Output` - Description: Parses JSON string with the schema. - **S.parseAsyncOrThrow** - Interface: `(unknown, Schema) => Promise` - Description: Parses any value with the schema having async transformations. ``` -------------------------------- ### Instance Validation with S.instance in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage S.instance(Class) checks if the input value is an instance of a specific class. This is crucial for validating inputs against classes, especially those from third-party libraries, ensuring correct type and structure. ```typescript class Test { name: string; } const TestSchema = S.instance(Test); const blob: any = "whatever"; S.parseOrThrow(new Test(), TestSchema); // passes S.parseOrThrow(blob, TestSchema); // throws S.Error: Failed parsing: Expected Test, received "whatever" ``` -------------------------------- ### Conversion Operations (No Validation) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage These operations transform values to the output type without performing input type validation. Use with caution. ```APIDOC ## Conversion Operations (No Validation) ### Description Transforms values to the output type without type validation. Refinements and transforms in the schema will still be applied. ### Operations - **S.convertOrThrow** - Interface: `(Input, Schema) => Output` - Description: Converts input value to the output type. - **S.convertToJsonOrThrow** - Interface: `(Input, Schema) => Json` - Description: Converts input value to JSON. - **S.convertToJsonStringOrThrow** - Interface: `(Input, Schema) => string` - Description: Converts input value to JSON string. ``` -------------------------------- ### Error Handling with S.parseOrThrow Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Demonstrates how `S.parseOrThrow` throws an `S.Error` when parsing fails. The error object contains detailed information about the parsing problem, aiding in identifying and resolving issues. ```typescript S.parseOrThrow(true, S.schema(false)); // => Throws S.Error with the following message: Failed parsing: Expected false, received true". ``` -------------------------------- ### String Refinements and Transformations in Sury (TypeScript) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Details various built-in string refinements provided by Sury, such as length constraints (`max`, `min`, `length`), format validation (`email`, `url`, `uuid`, `cuid`, `pattern`, `datetime`), and transformations (`trim`). Custom error messages can also be provided. ```typescript S.max(S.string, 5); // String must be 5 or fewer characters long S.min(S.string, 5); // String must be 5 or more characters long S.length(S.string, 5); // String must be exactly 5 characters long S.email(S.string); // Invalid email address S.url(S.string); // Invalid url S.uuid(S.string); // Invalid UUID S.cuid(S.string); // Invalid CUID S.pattern(S.string, %re(`/[0-9]/`)); // Invalid S.datetime(S.string); // Invalid datetime string! Expected UTC S.trim(S.string); // trim whitespaces S.min(S.string, 1, "String can't be empty"); S.length(S.string, 5, "SMS code should be 5 digits long"); ``` -------------------------------- ### Brand Schema Output with S.brand Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Use S.brand to attach a type-only nominal brand to a schema's output. This enhances type safety in TypeScript by ensuring only validated values acquire the brand. It does not alter runtime behavior. ```typescript // Brand a string as a UserId const UserId = S.string.with(S.brand, "UserId"); type UserId = S.Infer; // S.Brand const id: UserId = S.parseOrThrow("u_123", UserId); // OK const asString: string = id; // OK: branded value is assignable to string // @ts-expect-error - A plain string is not assignable to a branded string const notId: UserId = "u_123"; const even = S.number .with(S.refine, (value, s) => { if (value % 2 !== 0) s.fail("Expected an even number"); }) .with(S.brand, "even"); type Even = S.Infer; // S.Brand const good: Even = S.parseOrThrow(2, even); // OK // @ts-expect-error - number is not assignable to brand "even" const bad: Even = 5; ``` -------------------------------- ### Transform Tuples with S.tuple and item in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage S.tuple combined with s.item allows transforming incoming tuples into more convenient data structures. This provides a flexible way to parse and shape tuple data with zero performance overhead. ```typescript const athleteSchema = S.tuple((s) => ({ name: s.item(0, S.string), jerseyNumber: s.item(1, S.number), statistics: s.item( 2, S.schema({ pointsScored: S.number, }) ), })); type Athlete = S.Infer; // type Athlete = { // name: string; // jerseyNumber: number; // statistics: { pointsScored: number }; // } ``` -------------------------------- ### Define Fixed-Size Tuples with S.schema in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage The S.schema function can define tuples with a fixed number of elements, where each element can have a different type. This is useful for structured data like coordinates or records with predefined fields. ```typescript const athleteSchema = S.schema([ S.string, // name S.number, // jersey number { pointsScored: S.number, }, // statistics ]); type Athlete = S.Infer; // type Athlete = [string, number, { pointsScored: number }] ``` -------------------------------- ### Safe Operations (Result Type) Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Provides safe wrappers for operations to catch errors and return a Result type, facilitating error handling. ```APIDOC ## Safe Operations (Result Type) ### Description Wraps operations to catch errors and return a `Result` type, simplifying error handling. ### Helpers - **S.safe** - Usage: `S.safe(() => operation())` - Description: Catches synchronous errors and wraps the operation's outcome in a `Result` type. - **S.safeAsync** - Usage: `S.safeAsync(async () => operation())` - Description: Catches asynchronous errors and wraps the operation's outcome in a `Result` type. ``` -------------------------------- ### Record Validation with S.record in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage S.record(valueSchema) validates objects where all values conform to a specified schema, irrespective of the keys. This is ideal for validating associative arrays or caches where only value types are constrained. ```typescript const numberCacheSchema = S.record(S.number); type NumberCache = S.Infer; // => { [k: string]: number } ``` -------------------------------- ### Enforce Literal Type with 'as const' or S.schema in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Shows how to enforce a specific literal type for a field within an object schema, either by using `as const` or by wrapping the literal value with `S.schema`. This is useful for discriminated unions. ```typescript S.schema({ kind: "human" as const, // Or kind: S.schema("human"), }); ``` -------------------------------- ### Enum Schema Definition with S.union in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage S.union can be used to create schemas for enum-like types by passing an array of literal string values. This provides type safety for restricted sets of string inputs. ```typescript const schema = S.union(["Win", "Draw", "Loss"]); typeof S.Infer; // Win | Draw | Loss ``` -------------------------------- ### Discriminated Unions with S.union in TypeScript Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage S.union can be used to define discriminated unions where each member schema has a common literal field (discriminant) that determines its type. This allows for precise validation of complex, variant data structures. ```typescript // TypeScript type for reference: // type Shape = // | { kind: "circle"; radius: number } // | { kind: "square"; x: number } // | { kind: "triangle"; x: number; y: number }; const shapeSchema = S.union([ { kind: "circle" as const, radius: S.number, }, { kind: "square" as const, x: S.number, }, { kind: "triangle" as const, x: S.number, y: S.number, }, ]); ``` -------------------------------- ### Define Recursive Schemas with S.recursive Source: https://raw.githubusercontent.com/DZakh/sury/refs/heads/main/docs/js-usage Define recursive schemas in Sury for nested data structures like trees. Due to TypeScript's inference, you need to explicitly specify the type parameter for S.recursive to ensure correct type checking. ```typescript type Node = { id: string; children: Node[]; }; const nodeSchema = S.recursive("Node", (nodeSchema) => S.schema({ id: S.string, children: S.array(nodeSchema), }) ); // Note: Passing cyclical data will cause an infinite loop. ```