diff --git a/README.md b/README.md
index 80d2418..6ad6083 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,437 @@ The schema produced by `fg.form()` has two methods:
- `.parse()` that returns the parsed form data or throws an error if the form data is invalid.
- `.safeParse()` that returns an object with this shape: `{ success: true, data: Output } | { success: false, error: Error }`.
+## Complete API
+
+
interface FormInput
+
+Base interface for all form inputs.
+
+```ts
+interface FormInput {
+ /** Attributes given when creating the validator. */
+ attributes: Record;
+ /**
+ * Transforms the output of the validator into another value.
+ *
+ * @example
+ * text().transform((value) => value.length);
+ *
+ * @param fn - The transformation function.
+ * @param catcher - In case the transformation function throws, this function
+ * is called to generate an error message.
+ */
+ transform(fn: (value: T) => U, catcher?: (error: unknown) => string): FormInput;
+ /** Adds a custom validation to the input. */
+ refine(fn: (value: T) => value is U, message?: string | ((value: T) => string)): FormInput;
+ refine(fn: (value: T) => unknown, message?: string | ((value: T) => string)): FormInput;
+ /**
+ * Makes the field optional, for inputs that may be removed or added
+ * dynamically to the form.
+ *
+ * It returns `undefined` instead of `null` to differentiate between a missing
+ * field (`undefined`) and a field with an empty value (`null`).
+ *
+ * You may provide a default value to be used when the field is missing.
+ */
+ optional(): FormInput;
+ optional(value: U): FormInput;
+ /** @private @internal */
+ [safeParse]: (data: ReadonlyFormData, name: string) => Result;
+}
+```
+
+
+
+
class FormgatorError
+
+An error thrown when using `form.parse()`. It has two fields: `issues` and `accepted`,
+containing the issues and accepted values respectively.
+
+Type-safety cannot be guaranteed when using exceptions. If you want type-safety, use
+`form.safeParse()`.
+
+
+
+
type Issues
+
+Transforms an object of form inputs into the issues object.
+
+```ts
+type Issues = Record>> = {
+ [K in keyof T]?: ValidationIssue;
+} extends infer O ? {
+ [K in keyof O]: O[K];
+} : never;
+```
+
+
+
+
type Output
+
+Transforms an object of form inputs into the success object.
+
+```ts
+type Output = Record>> = {
+ [K in keyof T]: T[K] extends FormInput ? U : never;
+} extends infer O ? {
+ [K in keyof O]: O[K];
+} : never;
+```
+
+
+
+
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+
+The `value` attribute is not supported, use `select({ multiple: true })`
+instead if you want to handle several checkboxes with the same name but
+different values.
+
+
+
+
function color()
+
+`` form input validator.
+
+It does not support any attributes.
+
+The output value is a string with the format `#rrggbb`.
+
+
+
+
function custom()
+
+A custom validator, transformer, whatever, for you to implement if formgator falls short on
+features.
+
+Returning a value will be considered a success, while throwing an error will be considered a
+validation issue. The error message will be used as the issue message.
+
+
+
+
function date()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `min` - Minimum date.
+- `max` - Maximum date.
+
+The output value is a string with the format `yyyy-mm-dd`.
+
+
+
+
function datetimeLocal()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `min` - Minimum date.
+- `max` - Maximum date.
+
+The output value is a string with the format `yyyy-mm-ddThh:mm`.
+
+
+
+
function email()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `maxlength` - Maximum length of the input.
+- `minlength` - Minimum length of the input.
+- `pattern` - Regular expression pattern to match by each email address.
+- `multiple` - Whether the input allows multiple comma-separated email
+ addresses.
+
+
+
+
function file()
+
+`` form input validator.
+
+Supported attributes:
+
+- `multiple` - Whether the input allows multiple files.
+- `required` - Whether the input is required.
+- `accept` - The accepted file types, as an array of MIME types (`image/png`),
+ MIME wildcards (`image/*`), or file extensions (`.png`).
+
+
+
+
function form()
+
+Creates a form validator from a record of form inputs.
+
+The return schema has two methods: `parse` and `safeParse`:
+- `parse(data: FormData)` returns the data object if valid, throws a `FormgatorError` otherwise.
+- `safeParse(data: FormData)` returns an object with `success` a success boolean flag, and
+ either `data` or `error` containing the parsed data or the issues respectively.
+
+
+
+
function hidden()
+
+`` form input validator.
+
+Not very useful, but included for completeness.
+
+
+
+
function image()
+
+`` form input validator.
+
+
+
+
function month()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `min` - Minimum date.
+- `max` - Maximum date.
+
+The output value is a string with the format `yyyy-mm-dd`.
+
+
+
+
function number()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `min` - Minimum value.
+- `max` - Maximum value.
+
+
+
+
function password()
+
+`` form input validator.
+
+Does not accept new lines, use `textarea()` instead.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `maxlength` - Maximum length of the input.
+- `minlength` - Minimum length of the input.
+- `pattern` - Regular expression pattern to match.
+
+
+
+
function radio()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+
+
+
+
function range()
+
+`` form input validator.
+
+Supported attributes:
+
+- `min` - Minimum value, defaults to `0`.
+- `max` - Maximum value, defaults to `100`.
+- `step` - Step value, defaults to `1`.
+
+
+
+
function search()
+
+`` form input validator.
+
+Does not accept new lines, use `textarea()` instead.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `maxlength` - Maximum length of the input.
+- `minlength` - Minimum length of the input.
+- `pattern` - Regular expression pattern to match.
+
+
+
+
function select()
+
+`
+
+
function splat()
+
+Allows you to splat attributes into Svelte HTML template.
+
+This feature is considered experimental and may be removed in the future.
+
+
+
+
function tel()
+
+`` form input validator.
+
+Does not accept new lines, use `textarea()` instead.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `maxlength` - Maximum length of the input.
+- `minlength` - Minimum length of the input.
+- `pattern` - Regular expression pattern to match.
+
+
+
+
function text()
+
+`` form input validator.
+
+Does not accept new lines, use `textarea()` instead.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `maxlength` - Maximum length of the input.
+- `minlength` - Minimum length of the input.
+- `pattern` - Regular expression pattern to match.
+
+
+
+
function textarea()
+
+`
+
+
function time()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `min` - Minimum date.
+- `max` - Maximum date.
+
+The output value is a string with the format `yyyy-mm-dd`.
+
+
+
+
function url()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `maxlength` - Maximum length of the input.
+- `minlength` - Minimum length of the input.
+- `pattern` - Regular expression pattern to match.
+
+
+
+
function week()
+
+`` form input validator.
+
+Supported attributes:
+
+- `required` - Whether the input is required.
+- `min` - Minimum date.
+- `max` - Maximum date.
+
+The output value is a string with the format `yyyy-Www` (e.g. `1999-W01`).
+
+
+
## Errors
An invalid form will produce an error with the same shape as your form schema:
diff --git a/docs/src/index.ts b/docs/src/index.ts
index 5bd76dc..4a41e8c 100644
--- a/docs/src/index.ts
+++ b/docs/src/index.ts
@@ -1,4 +1,14 @@
import * as ts from "typescript";
+import * as fs from "node:fs";
+
+const file = fs.readFileSync("../README.md", "utf-8");
+
+const start = file.indexOf("## Complete API") + "## Complete API".length;
+const end = file.indexOf("## Errors");
+
+if (start === -1 || end === -1) throw new Error("Invalid README.md file");
+
+let out = "\n\n";
const program = ts.createProgram(["../dist/index.d.ts"], { noLib: true, strict: true });
const checker = program.getTypeChecker();
@@ -11,16 +21,29 @@ for (const sourceFile of program.getSourceFiles()) {
if (!root) continue;
for (const symbol of checker.getExportsOfModule(root)) {
- console.log(symbol.getName());
const source = checker.getAliasedSymbol(symbol);
- const node = checker.typeToTypeNode(
- checker.getTypeOfSymbol(source),
- undefined,
- ts.NodeBuilderFlags.NoTruncation | ts.NodeBuilderFlags.MultilineObjectLiterals,
- )!;
- console.log(
- printer.printNode(ts.EmitHint.Unspecified, node, sourceFile),
- ts.displayPartsToString(source.getDocumentationComment(checker)),
- );
+ const declaration = source.getDeclarations()?.[0];
+
+ if (!declaration) continue;
+
+ const kind = {
+ [ts.SyntaxKind.FunctionDeclaration]: "function",
+ [ts.SyntaxKind.ClassDeclaration]: "class",
+ [ts.SyntaxKind.InterfaceDeclaration]: "interface",
+ [ts.SyntaxKind.TypeAliasDeclaration]: "type",
+ }[declaration.kind];
+
+ out += `
\n\n`;
+ out += `${ts.displayPartsToString(source.getDocumentationComment(checker))}\n\n`;
+
+ if (kind === "interface" || kind === "type") {
+ // @ts-expect-error I have no idea why this works, but it works at skipping the docblock
+ declaration.pos += 1;
+ out += `\`\`\`ts\n${printer.printNode(ts.EmitHint.Unspecified, declaration, sourceFile)}\n\`\`\`\n\n`;
+ }
+
+ out += "\n\n";
}
}
+
+fs.writeFileSync("../README.md", file.slice(0, start) + out + file.slice(end));
diff --git a/src/definitions.ts b/src/definitions.ts
index cec96c0..125ddb3 100644
--- a/src/definitions.ts
+++ b/src/definitions.ts
@@ -15,6 +15,9 @@ export interface ReadonlyFormData {
getAll(name: string): Array;
}
+/**
+ * All possible validation issues that can be returned by a form input.
+ */
export type ValidationIssue =
| { code: "accept"; message: string }
| { code: "custom"; message: string }
@@ -30,6 +33,9 @@ export type ValidationIssue =
| { code: "transform"; message: string }
| { code: "type"; message: string };
+/**
+ * Base interface for all form inputs.
+ */
export interface FormInput {
/** Attributes given when creating the validator. */
attributes: Record;