# Headless parsing

Parse Markdown into text and a syntax tree without creating a reading component.

Use `@quirekit/incremark-core` to analyze Markdown or supply a syntax tree to your own renderer. This entry imports neither Vue nor UI and creates no editable view. It currently still depends on CodeMirror modules through MSFE.

## 1. Parse a complete text

When all text has arrived, call `parseMarkdown()`:

```ts [Parse complete text]
import { parseMarkdown } from '@quirekit/incremark-core'

const state = parseMarkdown('# Hello')
const text = state.doc.toString()
```

`state` is a CodeMirror `EditorState` used read-only. It contains text, a syntax tree and extension-maintained semantics; it is neither HTML nor mdast/hast. The resulting `text` is still `# Hello`. Persist the original Markdown rather than serializing `EditorState`.

## 2. Receive text over time

Retain one `MarkdownStream` and pass each new piece to `append()`:

```ts [Append one piece]
import { MarkdownStream } from '@quirekit/incremark-core'

const stream = new MarkdownStream()
stream.append('# Hello')
const complete = stream.advance(4)
const snapshot = stream.state
```

`append()` takes only the newly received portion. If the application already accumulates the full text, use `stream.update(fullText)` instead. `advance(4)` gives the parser approximately four milliseconds of extra budget. It returns `true` when syntax and reference grouping for the current text are complete; otherwise the application schedules another call.

The class owns no timers. Do not spin synchronously until it returns `true`, which would block the interface. The budget is a cooperative hint, not a strict four-millisecond limit; reference checks and interface rendering also take time. You can read `snapshot` while parsing is pending, but it is not yet a final result.

## 3. Read the syntax tree

Get the Lezer tree from a completed state:

```ts [Read syntax structure]
import { syntaxTree } from '@quirekit/cm-language'

const tree = syntaxTree(state)
const description = tree.toString()
```

For `# Hello`, the compact description is `Document(ATXHeading1(HeaderMark))`: a document containing a level-one heading and its `#` marker. Use the tree's cursor, firstChild and nextSibling APIs to traverse node kinds and UTF-16 ranges.

`state.doc` uses normalized newlines. Extensions maintain cross-block relationships such as links and footnotes; a source prefix alone does not establish a final link target. Tree descriptions are useful for debugging, not persistence.

## Complete function

`recipes/snapshot.ts` combines steps one and three as `inspectMarkdown(source)`, returning the state, text and tree description. Consult this single-file function when integrating an analysis tool:

### recipes/snapshot.ts

```ts
import { parseMarkdown } from "@quirekit/incremark-core";
import { syntaxTree } from "@quirekit/cm-language";

/**
 * Parse once without mounting an editor or creating Vue components.
 * @param source - Exact Markdown supplied by the host.
 * @returns The immutable snapshot, canonical text and a compact syntax-tree description.
 */
export function inspectMarkdown(source: string) {
  const state = parseMarkdown(source);
  return { state, text: state.doc.toString(), syntax: syntaxTree(state).toString() };
}

```
