/** * `@formspec/dsl` - DSL functions for defining FormSpec forms * * This package provides the builder functions for creating form specifications: * - `field.*` - Field builders (text, number, boolean, enum, dynamicEnum) * - `group()` - Visual grouping * - `when()` + `is()` - Conditional visibility * - `formspec()` - Top-level form definition * * @example * ```typescript * import { formspec, field, group, when, is } from "@formspec/dsl"; * * const InvoiceForm = formspec( * group("Customer", * field.text("customerName", { label: "Customer Name" }), * field.dynamicEnum("country", "fetch_countries", { label: "Country" }), * ), * group("Invoice Details", * field.number("amount", { label: "Amount", min: 0 }), * field.enum("status", ["draft", "sent", "paid"] as const), * when(is("status", "draft"), * field.text("internalNotes", { label: "Internal Notes" }), * ), * ), * ); * ``` * * @packageDocumentation */ /** * Union of all field types. * * @public */ export declare type AnyField = TextField | NumberField | BooleanField | StaticEnumField | DynamicEnumField | DynamicSchemaField | ArrayField | ObjectField; /** * apiName config shape under a required-or-optional policy. * * @public */ export declare type ApiNameConfig = Required extends true ? { readonly apiName: string; } : { readonly apiName?: string; }; /** * Argument tuple for policy-scoped array field builders. * * @public */ export declare type ArrayBuilderArgs[], Policy> = HasRequiredMetadata extends true ? readonly [config: ArrayFieldConfig, ...items: Items] : readonly [...items: Items] | readonly [config: ArrayFieldConfig, ...items: Items]; /** * An array field containing repeating items. * * Use this for lists of values (e.g., multiple addresses, line items). * * @typeParam N - The field name (string literal type) * @typeParam Items - The form elements that define each array item * * @public */ export declare interface ArrayField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as an array field */ readonly _field: "array"; /** Unique field identifier used as the schema key */ readonly name: N; /** Form elements that define the schema for each array item */ readonly items: Items; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Whether this field is required for form submission */ readonly required?: boolean; /** Minimum number of items required */ readonly minItems?: number; /** Maximum number of items allowed */ readonly maxItems?: number; } /** * Config accepted by policy-scoped array field builders. * * @public */ export declare type ArrayFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name" | "items">, Policy>; /** * A boolean checkbox field. * * @typeParam N - The field name (string literal type) * * @public */ export declare interface BooleanField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as a boolean field */ readonly _field: "boolean"; /** Unique field identifier used as the schema key */ readonly name: N; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Whether this field is required for form submission */ readonly required?: boolean; } /** * Config accepted by policy-scoped boolean field builders. * * @public */ export declare type BooleanFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name">, Policy>; /** * Builds a schema type from extracted fields. * * Maps field names to their inferred value types. * * @public */ export declare type BuildSchema = { [F in Fields as F extends { name: infer N extends string; } ? N : never]: F extends AnyField ? InferFieldValue : never; }; /** * A conditional wrapper that shows/hides elements based on another field's value. * * @typeParam FieldName - The field to check * @typeParam Value - The value that triggers the condition * @typeParam Elements - Tuple of contained form elements * * @public */ export declare interface Conditional { /** Type discriminator - identifies this as a conditional element */ readonly _type: "conditional"; /** Name of the field whose value determines visibility */ readonly field: FieldName; /** Value that triggers the condition (shows nested elements) */ readonly value: Value; /** Form elements shown when condition is met */ readonly elements: Elements; } /** * Field builder namespace containing functions to create each field type. * * @example * ```typescript * import { field } from "@formspec/dsl"; * * field.text("name", { label: "Full Name" }); * field.number("age", { min: 0, max: 150 }); * field.enum("status", ["draft", "sent", "paid"]); * field.dynamicEnum("country", "countries", { label: "Country" }); * ``` * * @public */ export declare function createFieldBuilders(): FieldBuilderNamespace; /** * Creates a DSL factory whose field builders and generated forms share a metadata policy. * * @public */ export declare function createFormSpecFactory(options?: { readonly metadata?: Policy; }): FormSpecFactory; /** * Registry for dynamic data sources. * * Extend this interface via module augmentation to register your data sources: * * @example * ```typescript * declare module "@formspec/core" { * interface DataSourceRegistry { * countries: { id: string; code: string; name: string }; * templates: { id: string; name: string; category: string }; * } * } * ``` * * @public */ export declare interface DataSourceRegistry { } /** * Gets the value type for a registered data source. * * If the source has an `id` property, that becomes the value type. * Otherwise, defaults to `string`. * * @public */ export declare type DataSourceValueType = Source extends keyof DataSourceRegistry ? DataSourceRegistry[Source] extends { id: infer ID; } ? ID : string : string; /** * Per-declaration metadata policy input. * * @public */ export declare interface DeclarationMetadataPolicyInput { /** Policy for JSON-facing serialized names. */ readonly apiName?: MetadataValuePolicyInput | undefined; /** Policy for human-facing labels and titles. */ readonly displayName?: MetadataValuePolicyInput | undefined; } /** * A field with dynamic enum options (fetched from a data source at runtime). * * @typeParam N - The field name (string literal type) * @typeParam Source - The data source key (from DataSourceRegistry) * * @public */ export declare interface DynamicEnumField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as a dynamic enum field */ readonly _field: "dynamic_enum"; /** Unique field identifier used as the schema key */ readonly name: N; /** Data source key for fetching options at runtime */ readonly source: Source; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Whether this field is required for form submission */ readonly required?: boolean; /** Field names whose values are needed to fetch options */ readonly params?: readonly string[]; } /** * Config accepted by policy-scoped dynamic enum field builders. * * @public */ export declare type DynamicEnumFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name" | "source">, Policy>; /** * A field that loads its schema dynamically (e.g., from an extension). * * @typeParam N - The field name (string literal type) * * @public */ export declare interface DynamicSchemaField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as a dynamic schema field */ readonly _field: "dynamic_schema"; /** Unique field identifier used as the schema key */ readonly name: N; /** Identifier for the schema source */ readonly schemaSource: string; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Whether this field is required for form submission */ readonly required?: boolean; /** Field names whose values are needed to configure the schema */ readonly params?: readonly string[]; } /** * Config accepted by policy-scoped dynamic schema field builders. * * @public */ export declare type DynamicSchemaFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name" | "schemaSource">, Policy>; /** * Enum-member display names remain unset unless authored explicitly. * * @public */ export declare interface EnumMemberDisplayNameDisabledPolicyInput { /** Leaves missing enum-member display names unresolved. */ readonly mode: "disabled"; } /** * Missing enum-member display names may be inferred. * * @public */ export declare interface EnumMemberDisplayNameInferIfMissingPolicyInput { /** Infers an enum-member display name when it is not authored explicitly. */ readonly mode: "infer-if-missing"; /** Callback used to infer the missing display name. */ readonly infer: EnumMemberMetadataInferenceFn; } /** * Enum-member display-name policy input. * * @public */ export declare type EnumMemberDisplayNamePolicyInput = EnumMemberDisplayNameDisabledPolicyInput | EnumMemberDisplayNameRequireExplicitPolicyInput | EnumMemberDisplayNameInferIfMissingPolicyInput; /** * Enum members must declare display names explicitly. * * @public */ export declare interface EnumMemberDisplayNameRequireExplicitPolicyInput { /** Fails when an enum member has no authored display name. */ readonly mode: "require-explicit"; } /** * Build-facing context passed to enum-member metadata inference callbacks. * * Enum members are resolved separately from declaration-level metadata so they * do not participate in the shared declaration-kind model used by TSDoc and * extension metadata slots. * * @public */ export declare interface EnumMemberMetadataInferenceContext { /** Authoring surface the enum originated from. */ readonly surface: MetadataAuthoringSurface; /** Logical member identifier used for policy inference. */ readonly logicalName: string; /** Underlying enum value before stringification. */ readonly memberValue: string | number; /** Optional build-only context supplied by the resolver. */ readonly buildContext?: unknown; } /** * Callback used to infer enum-member display names. * * @public */ export declare type EnumMemberMetadataInferenceFn = (context: EnumMemberMetadataInferenceContext) => string; /** * User-facing enum-member metadata policy input. * * @public */ export declare interface EnumMemberMetadataPolicyInput { /** Policy for human-facing enum-member labels. */ readonly displayName?: EnumMemberDisplayNamePolicyInput | undefined; } /** * An enum option with a separate ID and display label. * * Use this when the stored value (id) should differ from the display text (label). * * @public */ export declare interface EnumOption { /** Stored enum value written into submitted data. */ readonly id: string; /** Human-readable label shown to end users. */ readonly label: string; } /** * Valid enum option types: either plain strings or objects with id/label. * * @public */ export declare type EnumOptionValue = string | EnumOption; /** * Predicate types for conditional logic. * * Predicates are used with `when()` to define conditions in a readable way. */ /** * An equality predicate that checks if a field equals a specific value. * * @typeParam K - The field name to check * @typeParam V - The value to compare against * * @public */ export declare interface EqualsPredicate { /** Predicate type discriminator */ readonly _predicate: "equals"; /** Name of the field to check */ readonly field: K; /** Value that the field must equal */ readonly value: V; } /** * Extracts fields that ARE inside conditionals. * These fields may or may not be visible and should be optional in the inferred schema. * * @example * ```typescript * // Given a form with conditional fields: * const form = formspec( * field.text("name"), // non-conditional (skipped) * when(is("type", "business"), * field.text("company"), // conditional (extracted) * field.text("taxId"), // conditional (extracted) * ), * ); * * // ExtractConditionalFields extracts: TextField<"company"> | TextField<"taxId"> * ``` * * @public */ export declare type ExtractConditionalFields = E extends AnyField ? never : E extends Group ? ExtractConditionalFieldsFromArray : E extends Conditional ? ExtractFieldsFromArray : never; /** * Extracts conditional fields from an array of elements. * * @example * ```typescript * type Elements = readonly [ * TextField<"name">, * Conditional<"type", "business", readonly [TextField<"company">]> * ]; * type Fields = ExtractConditionalFieldsFromArray; * // TextField<"company"> * ``` * * @public */ export declare type ExtractConditionalFieldsFromArray = Elements extends readonly [ infer First, ...infer Rest ] ? ExtractConditionalFields | ExtractConditionalFieldsFromArray : never; /** * Extracts all fields from a single element (recursively). * * - Field elements return themselves * - Groups extract fields from all child elements * - Conditionals extract fields from all child elements * * @public */ export declare type ExtractFields = E extends AnyField ? E : E extends Group ? ExtractFieldsFromArray : E extends Conditional ? ExtractFieldsFromArray : never; /** * Extracts fields from an array of elements. * * Recursively processes each element and unions the results. * * @public */ export declare type ExtractFieldsFromArray = Elements extends readonly [ infer First, ...infer Rest ] ? ExtractFields | ExtractFieldsFromArray : never; /** * Extracts fields that are NOT inside conditionals. * These fields are always visible and should be required in the inferred schema. * * @example * ```typescript * // Given a form with conditional and non-conditional fields: * const form = formspec( * field.text("name"), // non-conditional * field.number("age"), // non-conditional * when(is("type", "business"), * field.text("company"), // conditional (skipped) * ), * ); * * // ExtractNonConditionalFields extracts: TextField<"name"> | NumberField<"age"> * ``` * * @public */ export declare type ExtractNonConditionalFields = E extends AnyField ? E : E extends Group ? ExtractNonConditionalFieldsFromArray : E extends Conditional ? never : never; /** * Extracts non-conditional fields from an array of elements. * * @example * ```typescript * type Elements = readonly [TextField<"name">, NumberField<"age">]; * type Fields = ExtractNonConditionalFieldsFromArray; * // TextField<"name"> | NumberField<"age"> * ``` * * @public */ export declare type ExtractNonConditionalFieldsFromArray = Elements extends readonly [ infer First, ...infer Rest ] ? ExtractNonConditionalFields | ExtractNonConditionalFieldsFromArray : never; /** * Field builder namespace containing functions to create each field type. * * @public */ export declare const field: FieldBuilderNamespace; declare const FIELD_POLICY_BRAND: unique symbol; /** * Branded field element produced by a policy-scoped builder namespace. * * @public */ export declare type FieldBuilderElement = Element & { readonly [FIELD_POLICY_BRAND]: Policy extends undefined ? { readonly __formspecDefaultFieldPolicy: true; } : Policy; }; /** * Input element accepted by policy-scoped composite field builders. * * @public */ export declare type FieldBuilderInputElement = Policy extends undefined ? FormElement : FieldBuilderElement; /** * Namespace of field builder functions produced by the DSL. * * @public */ export declare interface FieldBuilderNamespace { /** Builds a text field. */ readonly text: (name: N, ...args: MaybeRequiredConfigArg, Policy>) => FieldBuilderElement>; /** Builds a number field. */ readonly number: (name: N, ...args: MaybeRequiredConfigArg, Policy>) => FieldBuilderElement>; /** Builds a boolean field. */ readonly boolean: (name: N, ...args: MaybeRequiredConfigArg, Policy>) => FieldBuilderElement>; /** Builds a static enum field. */ readonly enum: (name: N, options: O, ...args: MaybeRequiredConfigArg, Policy>) => FieldBuilderElement>; /** Builds a dynamic enum field. */ readonly dynamicEnum: (name: N, source: Source, ...args: MaybeRequiredConfigArg, Policy>) => FieldBuilderElement>; /** Builds a dynamic schema field. */ readonly dynamicSchema: (name: N, schemaSource: string, ...args: MaybeRequiredConfigArg, Policy>) => FieldBuilderElement>; /** Builds an array field, optionally with config as the second argument. */ readonly array: []>(name: N, ...args: ArrayBuilderArgs) => FieldBuilderElement>; /** Builds an array field with an explicit config object. */ readonly arrayWithConfig: []>(name: N, config: ArrayFieldConfig, ...items: Items) => FieldBuilderElement>; /** Builds an object field, optionally with config as the second argument. */ readonly object: []>(name: N, ...args: ObjectBuilderArgs) => FieldBuilderElement>; /** Builds an object field with an explicit config object. */ readonly objectWithConfig: []>(name: N, config: ObjectFieldConfig, ...properties: Properties) => FieldBuilderElement>; } /** * Field-specific metadata policy extracted from a broader metadata policy input. * * @public */ export declare type FieldMetadataPolicy = Policy extends { readonly field?: infer FieldPolicy; } ? FieldPolicy : undefined; /** * Utility type that flattens intersection types into a single object type. * * This improves TypeScript's display of inferred types and ensures * structural equality checks work correctly. * * @example * ```typescript * // Without FlattenIntersection: * type Messy = { a: string } & { b: number }; * // Displays as: { a: string } & { b: number } * * // With FlattenIntersection: * type Clean = FlattenIntersection<{ a: string } & { b: number }>; * // Displays as: { a: string; b: number } * ``` * * @public */ export declare type FlattenIntersection = { [K in keyof T]: T[K]; } & {}; /** * Union of all form element types (fields and structural elements). * * @public */ export declare type FormElement = AnyField | Group | Conditional; /** * A complete form specification. * * @typeParam Elements - Tuple of top-level form elements * * @public */ export declare interface FormSpec { /** Top-level form elements */ readonly elements: Elements; } /** * Creates a complete form specification. * * The structure IS the definition: * - Nesting with `group()` defines visual layout * - Nesting with `when()` defines conditional visibility * - Field type implies control type (text field → text input) * - Array position implies field ordering * * Schema is automatically inferred from all fields in the structure. * * @example * ```typescript * const InvoiceForm = formspec( * group("Customer", * field.text("customerName", { label: "Customer Name" }), * field.dynamicEnum("country", "fetch_countries", { label: "Country" }), * ), * group("Invoice Details", * field.number("amount", { label: "Amount", min: 0 }), * field.enum("status", ["draft", "sent", "paid"] as const), * when(is("status", "draft"), * field.text("internalNotes", { label: "Internal Notes" }), * ), * ), * ); * ``` * * @param elements - The top-level form elements * @returns A FormSpec descriptor * * @public */ export declare function formspec(...elements: Elements): FormSpec; /** * A configured DSL surface with policy-aware field builders and structure helpers. * * @public */ export declare interface FormSpecFactory { /** Field builders scoped to the factory metadata policy. */ readonly field: FieldBuilderNamespace; /** Creates a `FormSpec` carrying the factory metadata policy. */ readonly formspec: []>(...elements: Elements) => FormSpec; /** Creates a validating `FormSpec` carrying the factory metadata policy. */ readonly formspecWithValidation: []>(options: FormSpecOptions, ...elements: Elements) => FormSpec; /** Policy-scoped re-export of `group()`. */ readonly group: []>(label: string, ...elements: Elements) => FieldBuilderElement>; /** Policy-scoped re-export of `when()`. */ readonly when: []>(predicate: Predicate, ...elements: Elements) => FieldBuilderElement>; /** Re-export of `is()`. */ readonly is: typeof is; } /** * Options for creating a form specification. * * @public */ export declare interface FormSpecOptions { /** * Whether to validate the form structure. * - `true` or `"warn"`: Validate and log warnings/errors to console * - `"throw"`: Validate and throw an error if validation fails * - `false`: Skip validation (default in production for performance) * * @defaultValue false */ validate?: boolean | "warn" | "throw"; /** * Optional name for the form (used in validation messages). */ name?: string; } /** * Creates a complete form specification with validation options. * * @example * ```typescript * const form = formspecWithValidation( * { validate: true, name: "MyForm" }, * field.text("name"), * field.enum("status", ["draft", "sent"] as const), * when(is("status", "draft"), * field.text("notes"), * ), * ); * ``` * * @param options - Validation options * @param elements - The top-level form elements * @returns A FormSpec descriptor * * @public */ export declare function formspecWithValidation(options: FormSpecOptions, ...elements: Elements): FormSpec; /** * A visual grouping of form elements. * * Groups provide visual organization and can be rendered as fieldsets or sections. * * @typeParam Elements - Tuple of contained form elements * * @public */ export declare interface Group { /** Type discriminator - identifies this as a group element */ readonly _type: "group"; /** Display label for the group */ readonly label: string; /** Form elements contained within this group */ readonly elements: Elements; } /** * Creates a visual group of form elements. * * Groups provide visual organization and can be rendered as fieldsets or sections. * The nesting of groups defines the visual hierarchy of the form. * * @example * ```typescript * group("Customer Information", * field.text("name", { label: "Name" }), * field.text("email", { label: "Email" }), * ) * ``` * * @param label - The group's display label * @param elements - The form elements contained in this group * @returns A Group descriptor * * @public */ export declare function group(label: string, ...elements: Elements): Group; /** * Whether the active policy requires any explicit field metadata. * * @public */ export declare type HasRequiredMetadata = IsRequiredMetadata extends true ? true : IsRequiredMetadata extends true ? true : false; /** * Infers the value type from a single field. * * - TextField returns string * - NumberField returns number * - BooleanField returns boolean * - StaticEnumField returns union of option literals * - DynamicEnumField returns DataSourceValueType (usually string) * - DynamicSchemaField returns Record of string to unknown * - ArrayField returns array of inferred item schema * - ObjectField returns object of inferred property schema * * @example * ```typescript * // Simple fields * type T1 = InferFieldValue>; // string * type T2 = InferFieldValue>; // number * * // Enum fields * type T3 = InferFieldValue>; // "draft" | "sent" * * // Nested fields * type T4 = InferFieldValue]>>; // { name: string }[] * type T5 = InferFieldValue]>>; // { city: string } * ``` * * @public */ export declare type InferFieldValue = F extends TextField ? string : F extends NumberField ? number : F extends BooleanField ? boolean : F extends StaticEnumField ? O extends readonly EnumOption[] ? O[number]["id"] : O extends readonly string[] ? O[number] : never : F extends DynamicEnumField ? DataSourceValueType : F extends DynamicSchemaField ? Record : F extends ArrayField ? InferSchema[] : F extends ObjectField ? InferSchema : never; /** * Infers the schema type from a FormSpec. * * Convenience type that extracts elements and infers the schema. * * @example * ```typescript * const form = formspec(...); * type Schema = InferFormSchema; * ``` * * @public */ export declare type InferFormSchema> = F extends FormSpec ? InferSchema : never; /** * Infers the complete schema type from a form's elements. * * This is the main inference type that converts a form structure * into its corresponding TypeScript schema type. * * Non-conditional fields are required, conditional fields are optional. * * @example * ```typescript * const form = formspec( * field.text("name"), * field.number("age"), * field.enum("status", ["active", "inactive"] as const), * ); * * type Schema = InferSchema; * // { name: string; age: number; status: "active" | "inactive" } * * // Conditional fields become optional: * const formWithConditional = formspec( * field.enum("type", ["a", "b"] as const), * when(is("type", "a"), field.text("aField")), * ); * type ConditionalSchema = InferSchema; * // { type: "a" | "b"; aField?: string } * ``` * * @public */ export declare type InferSchema = FlattenIntersection> & Partial>>>; /** * Creates an equality predicate that checks if a field equals a specific value. * * Use this with `when()` to create readable conditional expressions: * * @example * ```typescript * // Show cardNumber field when paymentMethod is "card" * when(is("paymentMethod", "card"), * field.text("cardNumber", { label: "Card Number" }), * ) * ``` * * @typeParam K - The field name (inferred as string literal) * @typeParam V - The value type (inferred as literal) * @param field - The name of the field to check * @param value - The value the field must equal * @returns An EqualsPredicate for use with `when()` * @public */ export declare function is(field: K, value: V): EqualsPredicate; /** * Whether a specific metadata key is required by the active policy. * * @public */ export declare type IsRequiredMetadata = FieldMetadataPolicy extends Record ? FieldMetadataPolicy[Key] extends { readonly mode: "require-explicit"; } ? true : false : false; /** * Label/displayName config shape under a required-or-optional policy. * * @public */ export declare type LabelDisplayNameConfig = Required extends true ? { readonly label: string; readonly displayName?: never; } | { readonly label?: never; readonly displayName: string; } : { readonly label?: string; readonly displayName?: never; } | { readonly label?: never; readonly displayName?: string; } | { readonly label?: undefined; readonly displayName?: undefined; }; /** * Logs validation issues to the console. * * @param result - The validation result to log * @param formName - Optional name for the form (for better error messages) * * @public */ export declare function logValidationIssues(result: ValidationResult, formName?: string): void; /** * Optional-or-required config tuple driven by the active metadata policy. * * @public */ export declare type MaybeRequiredConfigArg = HasRequiredMetadata extends true ? readonly [config: Config] : readonly [config?: Config]; /** * Authoring surfaces that can contribute metadata. * * @public */ export declare type MetadataAuthoringSurface = "tsdoc" | "chain-dsl"; /** * Base field config augmented with metadata requirements from the active policy. * * @public */ export declare type MetadataAwareFieldConfig = Omit & ApiNameConfig> & LabelDisplayNameConfig>; /** * Declaration categories that metadata policy can target. * * @public */ export declare type MetadataDeclarationKind = "type" | "field" | "method"; /** * Build-facing context passed to metadata inference callbacks. * * `buildContext` is intentionally opaque so browser/runtime packages do not * need to depend on TypeScript compiler types. * * @public */ export declare interface MetadataInferenceContext { /** Authoring surface the metadata is being resolved for. */ readonly surface: MetadataAuthoringSurface; /** Declaration kind currently being resolved. */ readonly declarationKind: MetadataDeclarationKind; /** Logical identifier before any metadata policy is applied. */ readonly logicalName: string; /** Optional build-only context supplied by the resolver. */ readonly buildContext?: unknown; } /** * Callback used to infer a scalar metadata value. * * @public */ export declare type MetadataInferenceFn = (context: MetadataInferenceContext) => string; /** * Context passed to pluralization callbacks. * * @public */ export declare interface MetadataPluralizationContext extends MetadataInferenceContext { /** Singular value that pluralization should derive from. */ readonly singular: string; } /** * Pluralization disabled. * * @public */ export declare interface MetadataPluralizationDisabledPolicyInput { /** Disables automatic plural-value generation. */ readonly mode?: "disabled" | undefined; } /** * Callback used to derive plural metadata from a singular value. * * @public */ export declare type MetadataPluralizationFn = (context: MetadataPluralizationContext) => string; /** * Pluralization may be inferred when absent. * * @public */ export declare interface MetadataPluralizationInferIfMissingPolicyInput { /** Infers plural values whenever no explicit plural is present. */ readonly mode: "infer-if-missing"; /** Callback that derives a plural form from the resolved singular value. */ readonly inflect: MetadataPluralizationFn; } /** * Pluralization policy input. * * @public */ export declare type MetadataPluralizationPolicyInput = MetadataPluralizationDisabledPolicyInput | MetadataPluralizationRequireExplicitPolicyInput | MetadataPluralizationInferIfMissingPolicyInput; /** * Pluralization must be authored explicitly. * * @public */ export declare interface MetadataPluralizationRequireExplicitPolicyInput { /** Requires plural values to be authored directly. */ readonly mode: "require-explicit"; } /** * User-facing metadata policy configuration. * * @public */ export declare interface MetadataPolicyInput { /** Policy applied to named types and the analyzed root declaration. */ readonly type?: DeclarationMetadataPolicyInput | undefined; /** Policy applied to fields and object properties. */ readonly field?: DeclarationMetadataPolicyInput | undefined; /** Policy applied to callable/method declarations. */ readonly method?: DeclarationMetadataPolicyInput | undefined; /** Policy applied to enum-member display names during build-time IR resolution. */ readonly enumMember?: EnumMemberMetadataPolicyInput | undefined; } /** * Scalar metadata resolution modes. * * @public */ export declare type MetadataResolutionMode = "disabled" | "require-explicit" | "infer-if-missing"; /** * Shared metadata model and policy types. * * @public */ /** * Whether a resolved metadata value was authored directly or inferred by policy. * * @public */ export declare type MetadataSource = "explicit" | "inferred"; /** * Scalar metadata disabled unless provided explicitly elsewhere. * * @public */ export declare interface MetadataValueDisabledPolicyInput { /** Disables inference for this scalar metadata value. */ readonly mode?: "disabled" | undefined; /** Optional policy controlling plural forms of this scalar value. */ readonly pluralization?: MetadataPluralizationPolicyInput | undefined; } /** * Scalar metadata may be inferred when missing. * * @public */ export declare interface MetadataValueInferIfMissingPolicyInput { /** Infers this scalar metadata value when it is not authored explicitly. */ readonly mode: "infer-if-missing"; /** Callback used to infer the missing singular value. */ readonly infer: MetadataInferenceFn; /** Optional policy controlling plural forms of this scalar value. */ readonly pluralization?: MetadataPluralizationPolicyInput | undefined; } /** * Scalar metadata policy input. * * @public */ export declare type MetadataValuePolicyInput = MetadataValueDisabledPolicyInput | MetadataValueRequireExplicitPolicyInput | MetadataValueInferIfMissingPolicyInput; /** * Scalar metadata must be authored explicitly. * * @public */ export declare interface MetadataValueRequireExplicitPolicyInput { /** Requires this scalar metadata value to be authored directly. */ readonly mode: "require-explicit"; /** Optional policy controlling plural forms of this scalar value. */ readonly pluralization?: MetadataPluralizationPolicyInput | undefined; } /** * A numeric input field. * * @typeParam N - The field name (string literal type) * * @public */ export declare interface NumberField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as a number field */ readonly _field: "number"; /** Unique field identifier used as the schema key */ readonly name: N; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Minimum allowed value */ readonly min?: number; /** Maximum allowed value */ readonly max?: number; /** Whether this field is required for form submission */ readonly required?: boolean; /** Value must be a multiple of this number (use 1 for integer semantics) */ readonly multipleOf?: number; } /** * Config accepted by policy-scoped number field builders. * * @public */ export declare type NumberFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name">, Policy>; /** * Argument tuple for policy-scoped object field builders. * * @public */ export declare type ObjectBuilderArgs[], Policy> = HasRequiredMetadata extends true ? readonly [config: ObjectFieldConfig, ...properties: Properties] : readonly [...properties: Properties] | readonly [config: ObjectFieldConfig, ...properties: Properties]; /** * An object field containing nested properties. * * Use this for grouping related fields under a single key in the schema. * * @typeParam N - The field name (string literal type) * @typeParam Properties - The form elements that define the object's properties * * @public */ export declare interface ObjectField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as an object field */ readonly _field: "object"; /** Unique field identifier used as the schema key */ readonly name: N; /** Form elements that define the properties of this object */ readonly properties: Properties; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Whether this field is required for form submission */ readonly required?: boolean; } /** * Config accepted by policy-scoped object field builders. * * @public */ export declare type ObjectFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name" | "properties">, Policy>; /** * Union of all predicate types. * * Currently only supports equality, but can be extended with: * - `OneOfPredicate` - field value is one of several options * - `NotPredicate` - negation of another predicate * - `AndPredicate` / `OrPredicate` - logical combinations * * @public */ export declare type Predicate = EqualsPredicate; /** * Shared resolved metadata model carried through canonicalization and * generation. * * @public */ export declare interface ResolvedMetadata { /** Effective JSON-facing singular name. */ readonly apiName?: ResolvedScalarMetadata; /** Effective human-facing singular label. */ readonly displayName?: ResolvedScalarMetadata; /** Effective JSON-facing plural name, where applicable. */ readonly apiNamePlural?: ResolvedScalarMetadata; /** Effective human-facing plural label, where applicable. */ readonly displayNamePlural?: ResolvedScalarMetadata; } /** * A single resolved scalar metadata value plus its provenance. * * @public */ export declare interface ResolvedScalarMetadata { /** Effective metadata value after policy resolution. */ readonly value: string; /** Whether the value came from author intent or inference. */ readonly source: MetadataSource; } /** * A field with static enum options (known at compile time). * * Options can be plain strings or objects with `id` and `label` properties. * * @typeParam N - The field name (string literal type) * @typeParam O - Tuple of option values (strings or EnumOption objects) * * @public */ export declare interface StaticEnumField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as an enum field */ readonly _field: "enum"; /** Unique field identifier used as the schema key */ readonly name: N; /** Array of allowed option values */ readonly options: O; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Whether this field is required for form submission */ readonly required?: boolean; } /** * Config accepted by policy-scoped static enum field builders. * * @public */ export declare type StaticEnumFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name" | "options">, Policy>; /** * Form element type definitions. * * These types define the structure of form specifications. * The structure IS the definition - nesting implies layout and conditional logic. */ /** * A text input field. * * @typeParam N - The field name (string literal type) * * @public */ export declare interface TextField { /** Type discriminator for form elements */ readonly _type: "field"; /** Field type discriminator - identifies this as a text field */ readonly _field: "text"; /** Unique field identifier used as the schema key */ readonly name: N; /** Display label for the field */ readonly label?: string; /** Canonical display name for the field. Alias of `label` in the chain DSL. */ readonly displayName?: string; /** JSON-facing serialized name for the field. */ readonly apiName?: string; /** Placeholder text shown when field is empty */ readonly placeholder?: string; /** Whether this field is required for form submission */ readonly required?: boolean; /** Minimum string length */ readonly minLength?: number; /** Maximum string length */ readonly maxLength?: number; /** Regular expression pattern the value must match */ readonly pattern?: string; } /** * Config accepted by policy-scoped text field builders. * * @public */ export declare type TextFieldConfig = MetadataAwareFieldConfig, "_type" | "_field" | "name">, Policy>; /** * Validates a form specification for common issues. * * Checks for: * - Duplicate field names at the root level (warning) * - References to non-existent fields in conditionals (error) * * @example * ```typescript * const form = formspec( * field.text("name"), * field.text("name"), // Duplicate! * when("nonExistent", "value", // Reference to non-existent field! * field.text("extra"), * ), * ); * * const result = validateForm(form.elements); * // result.valid === false * // result.issues contains duplicate and reference errors * ``` * * @param elements - The form elements to validate * @returns Validation result with any issues found * * @public */ export declare function validateForm(elements: readonly FormElement[]): ValidationResult; /** * A validation issue found in a form specification. * * @public */ export declare interface ValidationIssue { /** Severity of the issue */ severity: ValidationSeverity; /** Human-readable message describing the issue */ message: string; /** Path to the element with the issue (e.g., "group.fieldName") */ path: string; } /** * Result of validating a form specification. * * @public */ export declare interface ValidationResult { /** Whether the form is valid (no errors, warnings are ok) */ valid: boolean; /** List of validation issues found */ issues: ValidationIssue[]; } /** * Validation issue severity levels. * * @public */ export declare type ValidationSeverity = "error" | "warning"; /** * Creates a conditional wrapper that shows elements based on a predicate. * * When the predicate evaluates to true, the contained elements are shown. * Otherwise, they are hidden (but still part of the schema). * * @example * ```typescript * import { is } from "@formspec/dsl"; * * field.enum("status", ["draft", "sent", "paid"] as const), * when(is("status", "draft"), * field.text("internalNotes", { label: "Internal Notes" }), * ) * ``` * * @param predicate - The condition to evaluate (use `is()` to create) * @param elements - The form elements to show when condition is met * @returns A Conditional descriptor * * @public */ export declare function when(predicate: Predicate, ...elements: Elements): Conditional; export { }