---
title: "Versions"
description: "A version comparison of a document with charts and diagrams compares what the document stores, never the picture."
canonical_url: "https://tiptap.dev/docs/diagrams/guides/versions"
---

# Versions

A version comparison of a document with charts and diagrams compares what the document stores, never the picture.

## What is compared

| Node      | Its state                                                                                |
| --------- | ---------------------------------------------------------------------------------------- |
| A chart   | Its attributes: its data, spec, Renderer, Data Source and when that source was last read |
| A diagram | Its source text, format, title and options                                               |

## With Tiptap's Compare

`@tiptap-pro/compare` compares the JSON of two documents. A chart or a diagram whose attributes
differ is reported as a changed block. Leave out the attributes that only serve showing or
editing, so they do not show up as changes:

```ts
import { compareDocuments } from '@tiptap-pro/compare'

const changeset = compareDocuments({
  schema: editor.schema,
  docA: olderVersion,
  docB: newerVersion,
  diffOptions: {
    // Compare's defaults, plus a chart's uploaded preview image and a table's Quick Input view
    ignoreAttributes: ['id', 'data-thread-id', '_hash', 'previewUrl', 'diagramInput'],
  },
})
```

| Attribute                   | Changes when                                                    | In a comparison                                                  |
| --------------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------- |
| `data`                      | values are edited, or a synchronization brings different data   | a change                                                         |
| `spec`                      | the type, title, colors, axes or references change              | a change                                                         |
| `renderer`                  | another Renderer is chosen; the data stays the same             | a change                                                         |
| `source`                    | the Data Source is linked, detached, or its address changes     | a change                                                         |
| `syncedAt`                  | the chart reads its Data Source, also when the data is the same | a change; add `'syncedAt'` to `ignoreAttributes` to leave it out |
| `previewUrl`                | a preview image is uploaded after a change                      | leave out                                                        |
| `diagramInput` (on a table) | the table is used as the Quick Input's table view               | leave out                                                        |

- A synchronization that brings the same data still records when the data was last checked.
- Whether that is a change worth showing is yours to decide with `ignoreAttributes`.

## Saying what changed in a chart

A comparison shows a changed chart as a whole. `describeChartChange` from
`@tiptap-pro/extension-diagrams/core` says what changed inside it, for a line such as
"February: 4 → 5, type: bar → line" next to the change:

```ts
import { describeChartChange } from '@tiptap-pro/extension-diagrams/core'

const change = describeChartChange({ before: olderChart.attrs, after: newerChart.attrs })

if (change.changed) {
  const cells =
    change.data?.cells.map(
      (cell) => `${cell.row} ${cell.column}: ${cell.before} → ${cell.after}`,
    ) ?? []
  const fields = change.spec.map(
    (field) => `${field.path}: ${String(field.before)} → ${String(field.after)}`,
  )
  console.log([...cells, ...fields].join(', '))
}
```

It returns:

| Field                            | What it holds                                                                     |
| -------------------------------- | --------------------------------------------------------------------------------- |
| `changed`                        | Whether anything below differs                                                    |
| `data`                           | `{ columnsAdded, columnsRemoved, rowsAdded, rowsRemoved, cells }`, or `null`      |
| `spec`                           | `{ path, before, after }` for every spec field that differs, such as `axes.y.min` |
| `renderer`, `source`, `syncedAt` | `{ before, after }`, or `null` when unchanged                                     |

- **Rows** are named by their label when every row has a distinct one, otherwise by their
  position.
- **Cells** are named by row and column header.
- **Attributes from any document** are accepted, also from before `syncedAt` was an attribute of
  its own.
- **What it cannot read** counts as an empty chart.
