Created
March 14, 2023 13:19
-
-
Save mgreystone/3cfeed5b8b08ef2a1a38228ddb8c6ee3 to your computer and use it in GitHub Desktop.
ot-prosemirror.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Node, Schema } from 'prosemirror-model' | |
import { Mappable, Mapping, MapResult, Step } from 'prosemirror-transform' | |
import type ShareDB from 'sharedb' | |
type Type = Parameters<typeof ShareDB.types.register>[0] | |
function mapToSide (source: Mappable, side: 'left' | 'right'): Mappable { | |
const assoc = side === 'left' ? -1 : 1 | |
return { | |
map (pos: number): number { | |
return source.map(pos, assoc) | |
}, | |
mapResult (pos: number): MapResult { | |
return source.mapResult(pos, assoc) | |
} | |
} | |
} | |
export function createProseMirrorType (name: string, uri: string, schema: Schema): Type { | |
function create (doc?: unknown): unknown { | |
let node | |
if (doc instanceof Node) node = doc | |
else if (doc != null) node = Node.fromJSON(schema, doc) | |
else node = schema.nodes.doc.createAndFill() ?? schema.nodes.doc.create() | |
return node.toJSON() | |
} | |
function apply (doc: unknown, steps: unknown[]): unknown { | |
const node = Node.fromJSON(schema, doc) | |
const next = steps.reduce<Node>((acc, step) => { | |
const result = deserializeStep(step).apply(acc) | |
if (result.failed != null || result.doc == null) { | |
throw new Error(result.failed ?? 'Could not apply ProseMirror Steps') | |
} | |
return result.doc | |
}, node) | |
return next.toJSON() | |
} | |
function transform (a: unknown[], b: unknown[], side: 'left' | 'right'): unknown[] { | |
const mapping = mapToSide(getMapping(b), side) | |
return a.map(step => { | |
const result = deserializeStep(step).map(mapping) | |
if (result == null) throw new Error('Could not transform ProseMirror Step') | |
return result.toJSON() | |
}) | |
} | |
function compose (a: unknown[], b: unknown[]): unknown[] { | |
return [...a, ...b] | |
} | |
function invertWithDoc (steps: unknown[], doc: unknown): unknown[] { | |
const result = [] | |
let node = Node.fromJSON(schema, doc) | |
for (let idx = steps.length - 1; idx >= 0; idx++) { | |
const inverted = Step.fromJSON(schema, steps[idx]).invert(node) | |
const stepResult = inverted.apply(node) | |
if (stepResult.failed != null || stepResult.doc == null) { | |
throw new Error(stepResult.failed ?? 'Could not invert ProseMirror Steps') | |
} | |
node = stepResult.doc | |
result.unshift(inverted.toJSON()) | |
} | |
return result | |
} | |
function transformCursor (cursor: number, steps: unknown[], isOwnOp: boolean): number { | |
const mapping = getMapping(steps) | |
return mapping.map(cursor, isOwnOp ? -1 : 1) | |
} | |
function serialize (doc: unknown): unknown { | |
return doc instanceof Node ? doc.toJSON() : doc | |
} | |
function deserialize (val: any): unknown { | |
return val | |
} | |
function deserializeStep (val: any): Step { | |
return val instanceof Step ? val : Step.fromJSON(schema, val) | |
} | |
function getMapping (steps: unknown[]): Mapping { | |
return new Mapping(steps.map(step => deserializeStep(step).getMap())) | |
} | |
return { | |
apply, | |
compose, | |
create, | |
deserialize, | |
invertWithDoc, | |
name, | |
serialize, | |
transform, | |
transformCursor, | |
uri | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment