---
title: "Versions"
description: "When you compare two versions of a document, charts and diagrams are compared by what the document stores, never by how they look."
canonical_url: "https://tiptap-docs.lin52025i.qzz.io/diagrams/guides/versions"
---

# Versions

When you compare two versions of a document, charts and diagrams are compared by what the document stores, never by how they look.

## What is compared

A chart is compared by its data, spec, Renderer, Data Source, delimiter and when that source was
last read. The table under [With Tiptap's Compare](https://tiptap-docs.lin52025i.qzz.io/diagrams/guides/versions.md#with-tiptaps-compare) says when each changes.
A diagram is compared by its source text, format, title, description, view and options. Add
`'view'` to `ignoreAttributes` if switching to the code view should not count as a change.

## With Tiptap's Compare

`@tiptap-pro/compare` compares the JSON of two documents. It reports a chart or a diagram whose
attributes differ as a changed block. Leave out the attributes that only matter for 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 or detached, or its address changes   | a change                                                          |
| `delimiter`                 | the rows are changed as text with another delimiter             | a change. Add `'delimiter'` to `ignoreAttributes` to leave it out |
| `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                                                         |

## Saying what changed in a chart

`describeChartChange` from `@tiptap-pro/extension-diagrams/core` tells you what changed inside a
chart, 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 different label. Otherwise they are named
  by their position.
- **Cells** are named by their row and their column header.
- **Attributes from any document** work, also from documents made before `syncedAt` was an
  attribute of its own.
- **Attributes it cannot read** count as an empty chart.
