CondeNast/atjson

Deficient Complex Boundary Behaviour

Closed this issue · 2 comments

@neilius encountered an issue where it's impossible to insert text between two adjacent annotations, and have the text not covered by either.

What do you expect to happen?

Given two annotations, { start: 10, end: 20 } and { start: 20, end: 30 }, it should be possible to insert text at position 20 and have the resulting annotations be { start: 10, end: 20 } and { start: 21, end: 31 }

This is not the default insertion behaviour, but it should be an option.

What happened instead?

Instead, we're able to modify the boundary behaviour for one or the other annotations, but not both. The default behaviour of insertText results in { start: 10, end: 21 } and { start: 21, end: 31 } (the first annotation is extended right, and the second annotation's coverage is unmodified), and the AdjacentBoundaryBehaviour.preserve behaviour results in { start: 10, end: 20 } and { start: 20, end: 31 } (i.e., the first annotation is unmodified and second annotation is extended left to include the new text).

📓 Example Document

Before: https://files.slack.com/files-pri/T5Y8VC3HU-FT9GKNJ9M/before.json
After (with preserve): https://files.slack.com/files-pri/T5Y8VC3HU-FT7MA4HMK/after.json

Proposal

@tim-evans @neilius and I discussed, and agreed that a good possible solution is to add a (backwards-compatible) way to specify boundary behaviour for text insertion for adjacent annotations both before and after the insertion. This should clarify the relevant bit of code, since currently both before and after boundaries are handled in the same method, despite being subtly different in their handling.

Suggestion for this:

  • Add a new enum option for AdjacentBoundaryBehaviour to handle the case provided above

  • Add a function overload to insertText, deleteText, and cut that take either an AdjacentBoundaryBehaviour option or an object that specifies a before / after (or leading / trailing option)

    For an example of operator overloads:

    function insertText(text: string, behaviour: { before: "modify"| "preserve", after: "modify" | "preserve"}): void;
    function insertText(text: string, behaviour: "modify" | "preserve" | "default"): void;
    function insertText(text: string, behaviour:  { before: "modify"| "preserve", after: "modify" |   "preserve"} | "modify" | "preserve") {
      // Implementation goes here
    }
  • Update Change (Insertion and Deletion) with before and after behavior instead of a collapsed joint behaviour.

  • Update handleInsert / handleDelete code in annotation.ts

Addressed in #401