Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify missing and undo/redo-related functions #28

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,23 @@ example, `require('ot-text').type.name` contains the text type's name.
- **uri**: *(Optional, will be required soon)* A canonical location for this type. The spec for the OT type should be at this address. Remember kids, Tim Berners-Lee says [cool URLs don't change](http://www.w3.org/Provider/Style/URI.html).
- **create([initialData]) -> snapshot**: A function to create the initial document snapshot. Create may accept initial snapshot data as its only argument. Either the return value must be a valid target for `JSON.stringify` or you must specify *serialize* and *deserialize* functions (described below).
- **apply(snapshot, op) -> snapshot'**: Apply an operation to a document snapshot. Returns the changed snapshot. For performance, old document must not be used after this function call, so apply may reuse and return the current snapshot object.
- **transform(op1, op2, side) -> op1'**: Transform op1 by op2. Return the new op1. Side is either `'left'` or `'right'`. It exists to break ties, for example if two operations insert at the same position in a string. Both op1 and op2 must not be modified by transform.
- **transform(op1, op2, side) -> op1'**: Transform op1 by op2. Return the new op1. Side is either `'left'` or `'right'`. It exists to break ties, for example if two operations insert at the same position in a string. Both op1 and op2 must not be modified by `transform`.
Transform must conform to Transform Property 1. That is, apply(apply(snapshot, op1), transform(op2, op1, 'left')) == apply(apply(snapshot, op2), transform(op1, op2, 'right')).
- **compose(op1, op2) -> op**: *(optional)* Compose op1 and op2 to produce a new operation. The new operation must subsume the behaviour of op1 and op2. Specifically, apply(apply(snapshot, op1), op2) == apply(snapshot, compose(op1, op2)). Note: transforming by a composed operation is *NOT* guaranteed to produce the same result as transforming by each operation in order. This function is optional, but unless you have a good reason to do otherwise, you should provide a compose function for your type.

### Optional properties

- **invert(op) -> op'**: *(optional)* Invert the given operation. The original operation must not be edited in the process. If supplied, apply(apply(snapshot, op), invert(op)) == snapshot.
- **transformX(op1, op2) -> [ op1', op2' ]**: *(optional)* Transform op1 by op2, and op2 by op1. Both op1 and op2 must not be modified by `transformX`. This function can be defined to improve performance, if the 2 transformations can be performed more efficiently together, than separately using the standard `transform`. transformX(op1, op2) == [ transform(op1, op2, 'left'), transform(op2, op1, 'right') ].
- **compose(op1, op2) -> op**: *(optional)* Compose op1 and op2 to produce a new operation. The new operation must subsume the behaviour of op1 and op2. Specifically, apply(apply(snapshot, op1), op2) == apply(snapshot, compose(op1, op2)). Note: transforming by a composed operation is *NOT* guaranteed to produce the same result as transforming by each operation in order. This function is optional, but unless you have a good reason to do otherwise, you should provide a compose function for your type.
- **composeSimilar(op1, op2) -> op OR null**: *(optional)* If op1 and op2 are "similar", then it's the same as `compose`. If op1 and op2 are not "similar", returns null. This function can be used to conditionally compose operations based on some criteria, eg edits at the same position in a text document. This way the "similar" operations could for example by undone as a single unit, instead of one by one.
- **invert(op) -> op'**: *(optional)* Invert the given operation. The original operation must not be edited in the process. apply(apply(snapshot, op), invert(op)) == snapshot.
- **applyAndInvert(snapshot, op) -> [ snapshot', op' ]**: *(optional)* Apply op to snapshot and return a new or modified snapshot and an inverted op. This function may be defined to make a type invertible even of `op` itself does not contain enough metadata to implement `invert` as a separate function. applyAndInvert(snapshot, op) == [ apply(snapshot, op), invert(op) ].
- **diff(snapshot1, snapshot2[, hint]) -> op**: *(optional)* Return an op which can be applied to snapshot1 to produce snapshot2. `hint` is optional and may be used to assit the diff algorithm, for example it could be a suggested editing position for a text type. apply(snapshot1, diff(snapshot1, snapshot2, hint)) == snapshot2.
- **diffX(snapshot1, snapshot2[, hint]) -> [ op1, op2 ]**: *(optional)* Returns ops which can be applied to one snapshot to produce the other. This function may be implemented to improve performance, if 2 diffs can be computed more efficiently together, than by 2 separate calls to `diff`. diffX(snapshot1, snapshot2, hint) == [ diffX(snapshot2, snapshot1, hint), diffX(snapshot1, snapshot2, hint) ].
- **normalize(op) -> op'**: *(optional)* Normalize an operation, converting it to a canonical representation. normalize(normalize(op)) == normalize(op).
- **transformCursor(cursor, op, isOwnOp) -> cursor'**: *(optional)* transform the specified cursor by the provided operation, so that the cursor moves forward or backward as content is added or removed before (or at) the cursor position. isOwnOp defines how the cursor should be transformed against content inserted *at* the cursor position. If isOwnOp is true, the cursor is moved after the content inserted at the original cursor position. If isOwnOp is false, the cursor remains before the content inserted at the original cursor position.
- **serialize(snapshot) -> data**: *(optional)* convert the document snapshot data into a form that may be passed to JSON.stringify. If you have a *serialize* function, you must have a *deserialize* function.
- **deserialize(data) -> snapshot**: *(optional)* convert data generated by *serialize* back into its internal snapshot format. deserialize(serialize(snapshot)) == snapshot. If you have a *deserialize* function, you must have a *serialize* function.
- **isNoop(op) -> boolean**: *(optional)* return true, if `op` is a no-op. Specifically, if isNoop(op) == true, then apply(snapshot, op) == snapshot.

> Do I need serialize and deserialize? Maybe JSON.stringify is sufficiently customizable..?

Expand Down