# Flow Parser Format Specification

This parser reads a lightweight graph DSL and returns a normalized graph object.

## Input Format

### 1. Statement Types

The parser accepts these statement types:

1. `NODE [ ... ]`  
Sets default attributes for all subsequently created normal nodes.

2. `EDGE [ ... ]`  
Sets default attributes for all subsequently created edges.

3. `NodeId [ ... ]` or `NodeId`  
Declares/updates a node.

4. `From -> To [ ... ]`, `From -.> To [ ... ]`, or `From *> To [ ... ]`  
Declares one edge (or multiple edges if chained).

5. `;` or blank lines  
Valid separators.

### 2. Line Endings and Separators

- A statement ends with `EOL`, `;`, or `EOF`.
- Attributes are written inside `[ ... ]`.
- Attributes are comma-separated and allow trailing commas.
- Newlines are allowed inside attribute blocks.

### 3. Comments

Supported comments:

- `# comment`
- `// comment`
- `/* block comment */`

### 4. Identifiers and Literals

- `IDENT`: starts with letter/underscore, then letters/digits/`_`/`-`/`.`.
- `QUOTED_STRING`: single or double quoted string.
- `NUMBER`: integer or float, supports optional leading `-`.
- `HEXNUMBER`: `0x...` (parsed as base 16 number).

### 5. Attribute Syntax

Each attribute is:

`key = value`

- `key`: `IDENT` or quoted string.
- `value`: `NUMBER`, `HEXNUMBER`, quoted string, or `IDENT`.

Value conversion:

- `NUMBER` -> JavaScript `Number`
- `HEXNUMBER` -> JavaScript `Number` via base-16 parsing
- quoted string -> unquoted string
- `IDENT` -> string

### 6. Node References in Edges

A node reference in an edge chain can be:

- `IDENT`
- `QUOTED_STRING`
- `*` (anonymous dummy node)
- `*name` (named dummy node)

Dummy node IDs generated by parser:

- anonymous `*` -> `_d$1`, `_d$2`, ...
- named `*name` -> `_d#name` (reused if referenced again)

### 7. Edge Operators

- `->` normal edge
- `-.>` dashed edge
- `*>` invisible edge

Dashed edge adds/overrides:

- `$dashed: true`

Invisible edge adds/overrides:

- `render: false`
- `$invisible: true`
- `elk.edge.thickness: 0`

### 8. Edge Chains

Chaining is supported:

`A -> B -> C`

This expands to:

- `A -> B`
- `B -> C`

If edge attributes are provided at chain end, they apply to every expanded edge in that chain.

### 9. Defaults and Special Handling

- Node defaults (`NODE`) are applied only when a normal node is first created.
- Edge defaults (`EDGE`) are merged into every created edge.
- Node attributes with keys starting with `elk.` are stored in `layoutOptions`; others go to `parameters`.
- Dummy nodes do not inherit `NODE` defaults.
- Parallel edges are disabled in current implementation; duplicate `(sourceId, targetId)` pairs are deduplicated with `first-wins`.

## Output Format

The parser returns:

```js
{
  nodes: [
    {
      id: string,
      parameters: { [key: string]: any },
      layoutOptions: { [key: string]: any }
    },
    ...
  ],
  edges: [
    {
      id: string,          // "_e1", "_e2", ...
      sourceId: string,
      targetId: string,
      parameters: { [key: string]: any }
    },
    ...
  ]
}
```

### Node Object

- `id`: node identifier (including generated dummy IDs).
- `parameters`: node attributes (non-`elk.*` keys).
- `layoutOptions`: node layout attributes (`elk.*` keys only).

### Edge Object

- `id`: auto-generated edge ID (`_e1`, `_e2`, ...).
- `sourceId`: source node ID.
- `targetId`: target node ID.
- `parameters`: merged edge properties:
  - current `EDGE` defaults
  - chain-level edge attributes (if any)
  - dashed-edge override for `-.>` (`$dashed: true`)
  - invisible-edge overrides for `*>`

## Minimal Example

```txt
NODE [color="blue", elk.direction=RIGHT]
EDGE [weight=2]

A [label="start"]
A -> *tmp -> "Task B" [kind=flow]
*tmp -.> D
*tmp *> C
```

Possible output shape:

```js
{
  nodes: [
    { id: "A", parameters: { color: "blue", label: "start" }, layoutOptions: { "elk.direction": "RIGHT" } },
    { id: "_d#tmp", parameters: { $dummy: true }, layoutOptions: {} },
    { id: "Task B", parameters: { color: "blue" }, layoutOptions: { "elk.direction": "RIGHT" } },
    { id: "D", parameters: { color: "blue" }, layoutOptions: { "elk.direction": "RIGHT" } },
    { id: "C", parameters: { color: "blue" }, layoutOptions: { "elk.direction": "RIGHT" } }
  ],
  edges: [
    { id: "_e1", sourceId: "A", targetId: "_d#tmp", parameters: { weight: 2, kind: "flow" } },
    { id: "_e2", sourceId: "_d#tmp", targetId: "Task B", parameters: { weight: 2, kind: "flow" } },
    { id: "_e3", sourceId: "_d#tmp", targetId: "D", parameters: { weight: 2, $dashed: true } },
    { id: "_e4", sourceId: "_d#tmp", targetId: "C", parameters: { weight: 2, render: false, $invisible: true, "elk.edge.thickness": 0 } }
  ]
}
```
