npm package: @formdata/parser
Description: Form-Data text form definition parser
Latest version: 1.141.0

# @formdata/parser

A specialized parser for Form-Data text-based form definitions. This package converts the `.fd` format into structured JSON that can be used to render forms.

## Installation

```bash
npm install @formdata/parser
```

## Features

- 📋 **Simple Syntax**: Parse the human-readable `.fd` format
- 🧩 **Form Structure**: Convert form definitions into structured objects
- ⚠️ **Error Handling**: Detailed error reporting for validation
- 🔍 **Diagnostics**: Editor-compatible diagnostics for IDEs
- 📐 **Extensible**: Supports numerous input types and validations

## Usage

```javascript
import { parseFormDefinition } from '@formdata/parser';

// Form definition in .fd format
const formContent = `
type form
name Contact form
action https://example.com/submit
message Thank you for your message!
design
    theme light
    background #f5f5f5

type h1
text Contact Us

type text
name full_name
label Full Name
placeholder Enter your name
validations required|length:3,50

type email
name email_address
label Email Address
placeholder you@example.com
validations required|email

type submit
label Send Message
`;

// Parse the definition
const result = parseFormDefinition(formContent);

console.log(result.name); // "Contact form"
console.log(result.endpoint); // "https://example.com/submit"
console.log(result.blocks); // Array of form elements
console.log(result.errors); // Array of any parsing errors
```

## Form Definition Format

The `.fd` format uses a simple syntax with indentation for nesting:

### Basic Structure

```
type <block_type>
property1 value1
property2 value2
nested_property
    key1 value1
    key2 value2
```

### Example Form

```
type form
name my_contact_form
action https://example.com/submit
message Thank you for contacting us!
design
    theme light
    background #f5f5f5

type h1
text Contact Us

type text
name full_name
label Full Name
placeholder Enter your full name
validations required|length:3,50

type email
name email
label Email Address
placeholder example@domain.com
validations required|email

type submit
label Send Message
```

## Supported Block Types

| Block Type      | Description           |
|-----------------|-----------------------|
| `form`          | The root form element |
| `step`          | Multi-step form step  |
| `h1` to `h6`    | Heading elements      |
| `text`          | Text input field      |
| `email`         | Email input field     |
| `tel`           | Telephone input field |
| `date`          | Date input field      |
| `textarea`      | Multiline text area   |
| `select`        | Dropdown select field |
| `cards`         | pick a card           |
| `radio`         | Radio button group    |
| `checkbox`      | Single checkbox       |
| `checkboxGroup` | Group of checkboxes   |
| `file`          | File upload field     |
| `slider`        | Range slider input    |
| `rating`        | Star rating input     |
| `signature`     | Signature pad input   |
| `button`        | Generic button        |
| `submit`        | Submit button         |
| `variable`      | Computed variable     |
| `hidden`        | Hidden form field     |
| `tag`           | Third-party tags (GTM, Facebook Pixel, etc.) |

## Common Properties

Most form elements support these properties:

| Property | Description |
|----------|-------------|
| `name` | Field name (used in form submission) |
| `label` | Display label for the field |
| `placeholder` | Placeholder text |
| `validations` | Validation rules separated by pipe (`\|`) |
| `default` | Default value |
| `help` | Help text displayed below the field |
| `classes` | Custom CSS classes for styling |
| `show` | Conditional visibility (boolean or expression) |
| `hide` | Conditional hiding (boolean or expression) |
| `disabled` | Disable the field |
| `readonly` | Make the field read-only |
| `attributes` | Custom HTML attributes |

### Signature Field

The signature field allows users to draw their signature:

```
type signature
name user_signature
label Please sign here
pen-color #0000ff
validations required
help Draw your signature in the box above
```

**Signature-specific properties:**
- `pen-color`: Color of the signature stroke (e.g., `#0000ff`, `rgb(0,0,255)`)

**Standard properties:**
- All common properties listed above (name, label, validations, help, classes, show, hide, disabled, readonly)

## Special Field Types

### Variable Fields

Variable fields are used to define computed values that can be referenced by other fields. They support templating expressions and are useful for calculations, scoring, or dynamic value generation.

```
type variable
name qualification_score
value {{ (10 if (budget | int) > 1000 else 0) + (10 if (timeline | int) < 30 else 0) }}
```

**Properties:**
- `name` (required): Variable name for referencing
- `value` (required): Computed value expression

### Hidden Fields

Hidden fields store values that are not visible to users but are included in form submissions. They can reference variables or contain static values.

```
type hidden
name score
value {{ qualification_score }}
```

**Properties:**
- `name` (required): Field name for form submission
- `value` (required): Field value (can be templated)

### Tag Blocks

Tag blocks allow you to embed third-party scripts and tracking codes like Google Tag Manager, Facebook Pixel, or other analytics tools. Unlike HTML blocks, tag content is not sanitized by the renderer.

```
type tag
placement head
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX');</script>
<!-- End Google Tag Manager -->
```

**Properties:**
- `placement` (optional): Where to place the tag - `head` or `body` (defaults to `head`)

**Usage:**
- Content is specified line-by-line after the properties
- Blank lines within content are skipped (not included)
- Content collection stops when a new block starts (same as HTML/CSS blocks)
- Content is not sanitized or escaped by the renderer
- Useful for tracking pixels, analytics, and third-party integrations

## Multi-Step Forms

Create multi-step forms by adding the `multi-step` property to the form block and defining `step` blocks to organize your form fields.

### Basic Multi-Step Syntax

```
type form
name my-survey
action https://example.com/submit
multi-step

type step
name personal-info
label Personal Information
next-label Continue

type text
name full_name
label Full Name
validations required

type email
name email
label Email
validations required

type step
name preferences
label Your Preferences
previous-label Back

type select
name category
label Category
options
    Option A
    Option B

type submit
label Submit
```

### Multi-Step Properties

**Form Block `multi-step` Property:**
- `multi-step`: (boolean) Enables multi-step form mode. Use `multi-step` or `multi-step true` to enable.

**Step Block Properties:**
- `name`: (required) Unique identifier for the step
- `label`: (optional) Display label shown to users
- `next-label`: (optional) Custom text for the "Next" button
- `previous-label`: (optional) Custom text for the "Previous" button
- `show`: (optional) Conditional visibility (supports templating, e.g., `show {{ field_name }}`)

### Key Features

- Form fields belong to the most recent step defined (no indentation required)
- Steps are sequential - define them in the order you want users to see them
- The submit button is automatically placed in the last step if not explicitly added
- Single-step forms work exactly as before (backward compatible)
- `css` and `tag` blocks can appear before steps (they're not part of the form flow)

### Output Format

Multi-step forms produce a different output structure:

```json
{
  "name": "my-survey",
  "multiStep": {},
  "steps": [
    {
      "name": "personal-info",
      "label": "Personal Information",
      "nextLabel": "Continue",
      "blocks": [
        { "$el": "form.text", "name": "full_name", "label": "Full Name" },
        { "$el": "form.email", "name": "email", "label": "Email" }
      ]
    },
    {
      "name": "preferences",
      "label": "Your Preferences",
      "previousLabel": "Back",
      "blocks": [
        { "$el": "form.select", "name": "category", "label": "Category" }
      ]
    }
  ]
}
```

## Indented Properties

Some properties use indentation for nested values:

### Design Settings

```
type form
name my_form
design
    theme dark
    background #333333
```

### Options for select, radio, cards and checkbox

```
type select
name fruit
label Choose a fruit
options
    Apple
        value apple
    Banana
        value banana
    Orange
        value orange
```

## Validation Rules

Validation rules are specified using a pipe-separated format:

```
validations required|length:3,50|email
```

Common validation rules:

- `required`: Field must not be empty
- `email`: Must be a valid email
- `length:min,max`: Text length constraints
- `min:value`: Minimum value (for numeric inputs)
- `max:value`: Maximum value (for numeric inputs)
- `matches:/regex/`: Custom regex pattern

## Error Handling

The parser returns detailed error information:

```javascript
const result = parseFormDefinition(formContent);

if (result.errors.length > 0) {
  result.errors.forEach(error => {
    console.log(`Line ${error.line}: ${error.message} (${error.code})`);
  });
}
```

Error codes:

- `PROPERTY_NOT_SUPPORTED`: Property not supported for the block type
- `MISSING_REQUIRED_PROPERTY`: Missing a required property
- `INVALID_INDENTATION`: Incorrect indentation structure
- `INVALID_BLOCK_TYPE`: Unknown block type
- `INVALID_PROPERTY_VALUE`: Invalid property value
- `DUPLICATE_PROPERTY`: Property defined multiple times

## Editor Integration

The parser includes utilities for IDE/editor integration:

```javascript
import { createDiagnostics } from '@formdata/parser';

// Create CodeMirror-compatible diagnostics
const diagnostics = createDiagnostics(formContent, result.errors);
```

## API Reference

### Main Functions

- `parseFormDefinition(text)`: Parse a form definition into a structured object
- `createDiagnostics(text, errors)`: Create editor-compatible diagnostics

### Constants

- `ERROR_CODES`: Enumeration of error code constants
- `PROPERTY_TYPES`: Property type classifications
- `BLOCK_TYPES`: Supported form block types
- `PROPERTIES`: Property configurations for each block type
- `ALL_PROPERTY_NAMES`: List of all valid property names

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT