UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

52 lines (48 loc) • 2.66 kB
import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils'; import { fg } from '@atlaskit/platform-feature-flags/fg'; import { getDiffableAttrNames } from '../decorations/utils/diffableAttrs'; import { getComparableExcerptIncludeAttrs, isExcerptInclude } from '../decorations/utils/excerptIncludeAttrs'; import { encodeCharacterWithMarks } from './encodeCharacterWithMarks'; /** * Attribute-aware token encoder for `prosemirror-changeset`. The default encoder * reduces a node to `node.type.name`, so an attribute-only change (e.g. a table * cell recolour) tokenises identically on both sides and goes undetected. This * folds the diffable attributes (from the shared `diffableAttrs` map) into the * open token so such changes register. */ // Stable composite token; attr names are pre-ordered by the caller. const encodeNodeWithAttrs = (nodeTypeName, attrs, attrNames) => { const parts = attrNames.map(name => { var _attrs$name; return `${name}=${JSON.stringify((_attrs$name = attrs[name]) !== null && _attrs$name !== void 0 ? _attrs$name : null)}`; }); return `${nodeTypeName}|${parts.join('|')}`; }; // Like the library default, but node types with a `diffableAttrs` rule fold their // attrs into the open token, and text characters fold in their marks. Node-end is // unchanged, hence `string | number`. export const attrAwareTokenEncoder = { encodeCharacter: (char, marks) => encodeCharacterWithMarks(char, marks), encodeNodeStart: node => { // A one-sided reference is not comparable from an isolated token. Attribute-step comparison // checks the reference when both versions have one. const attrs = fg('platform_editor_normalize_excerpt_diff') && node.type.name === 'extension' && isExcerptInclude(node.attrs) ? getComparableExcerptIncludeAttrs(node.attrs) : node.attrs; // Normalise variants (e.g. `panel_c1` → `panel`) so `diffableAttrs` needs one entry. const attrNames = getDiffableAttrNames(getBaseNodeTypeName(node.type), attrs !== null && attrs !== void 0 ? attrs : {}); if (attrNames && attrNames.length > 0) { return encodeNodeWithAttrs(node.type.name, attrs, attrNames); } return node.type.name; }, encodeNodeEnd: node => -typeID(node.type), compareTokens: (a, b) => a === b }; // Mirrors the library's private (unexported) `typeID` so node-end tokens match. function typeID(type) { const cache = type.schema.cached.changeSetIDs || (type.schema.cached.changeSetIDs = Object.create(null)); let id = cache[type.name]; if (id == null) { cache[type.name] = id = Object.keys(type.schema.nodes).indexOf(type.name) + 1; } return id; }