docx-diff-editor 1.0.26 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -228,12 +228,16 @@ declare function mergeDocuments(docA: ProseMirrorNode, docB: ProseMirrorNode, di
228
228
 
229
229
  /**
230
230
  * Create a trackInsert mark.
231
+ * @param author - The author of the change
232
+ * @param id - Optional ID to use (for linking with corresponding delete in replacements)
231
233
  */
232
- declare function createTrackInsertMark(author?: TrackChangeAuthor): ProseMirrorMark;
234
+ declare function createTrackInsertMark(author?: TrackChangeAuthor, id?: string): ProseMirrorMark;
233
235
  /**
234
236
  * Create a trackDelete mark.
237
+ * @param author - The author of the change
238
+ * @param id - Optional ID to use (for linking with corresponding insert in replacements)
235
239
  */
236
- declare function createTrackDeleteMark(author?: TrackChangeAuthor): ProseMirrorMark;
240
+ declare function createTrackDeleteMark(author?: TrackChangeAuthor, id?: string): ProseMirrorMark;
237
241
  /**
238
242
  * Create a trackFormat mark.
239
243
  */
package/dist/index.d.ts CHANGED
@@ -228,12 +228,16 @@ declare function mergeDocuments(docA: ProseMirrorNode, docB: ProseMirrorNode, di
228
228
 
229
229
  /**
230
230
  * Create a trackInsert mark.
231
+ * @param author - The author of the change
232
+ * @param id - Optional ID to use (for linking with corresponding delete in replacements)
231
233
  */
232
- declare function createTrackInsertMark(author?: TrackChangeAuthor): ProseMirrorMark;
234
+ declare function createTrackInsertMark(author?: TrackChangeAuthor, id?: string): ProseMirrorMark;
233
235
  /**
234
236
  * Create a trackDelete mark.
237
+ * @param author - The author of the change
238
+ * @param id - Optional ID to use (for linking with corresponding insert in replacements)
235
239
  */
236
- declare function createTrackDeleteMark(author?: TrackChangeAuthor): ProseMirrorMark;
240
+ declare function createTrackDeleteMark(author?: TrackChangeAuthor, id?: string): ProseMirrorMark;
237
241
  /**
238
242
  * Create a trackFormat mark.
239
243
  */
package/dist/index.js CHANGED
@@ -193,6 +193,18 @@ function getMarksAtPosition(spans, pos) {
193
193
  }
194
194
  return [];
195
195
  }
196
+ function hasDefinedAttributes(marks) {
197
+ if (!marks || marks.length === 0) return false;
198
+ for (const mark of marks) {
199
+ if (!mark.attrs) continue;
200
+ for (const value of Object.values(mark.attrs)) {
201
+ if (value !== void 0 && value !== null) {
202
+ return true;
203
+ }
204
+ }
205
+ }
206
+ return marks.some((m) => !m.attrs);
207
+ }
196
208
  function detectFormatChanges(spansA, spansB, segments) {
197
209
  const formatChanges = [];
198
210
  let posA = 0;
@@ -216,13 +228,17 @@ function detectFormatChanges(spansA, spansB, segments) {
216
228
  break;
217
229
  }
218
230
  }
219
- formatChanges.push({
220
- from: posA + startI,
221
- to: posA + i,
222
- text: segment.text.substring(startI, i),
223
- before: startMarksA,
224
- after: startMarksB
225
- });
231
+ if (hasDefinedAttributes(startMarksB) || hasDefinedAttributes(startMarksA)) {
232
+ if (hasDefinedAttributes(startMarksB)) {
233
+ formatChanges.push({
234
+ from: posA + startI,
235
+ to: posA + i,
236
+ text: segment.text.substring(startI, i),
237
+ before: startMarksA,
238
+ after: startMarksB
239
+ });
240
+ }
241
+ }
226
242
  } else {
227
243
  i++;
228
244
  }
@@ -280,11 +296,11 @@ function diffDocuments(docA, docB) {
280
296
  summary
281
297
  };
282
298
  }
283
- function createTrackInsertMark(author = DEFAULT_AUTHOR) {
299
+ function createTrackInsertMark(author = DEFAULT_AUTHOR, id) {
284
300
  return {
285
301
  type: "trackInsert",
286
302
  attrs: {
287
- id: uuid.v4(),
303
+ id: id ?? uuid.v4(),
288
304
  author: author.name,
289
305
  authorEmail: author.email,
290
306
  authorImage: "",
@@ -292,11 +308,11 @@ function createTrackInsertMark(author = DEFAULT_AUTHOR) {
292
308
  }
293
309
  };
294
310
  }
295
- function createTrackDeleteMark(author = DEFAULT_AUTHOR) {
311
+ function createTrackDeleteMark(author = DEFAULT_AUTHOR, id) {
296
312
  return {
297
313
  type: "trackDelete",
298
314
  attrs: {
299
- id: uuid.v4(),
315
+ id: id ?? uuid.v4(),
300
316
  author: author.name,
301
317
  authorEmail: author.email,
302
318
  authorImage: "",
@@ -337,17 +353,30 @@ function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
337
353
  return null;
338
354
  }
339
355
  let docAOffset = 0;
340
- for (const segment of diffResult.segments) {
356
+ const segments = diffResult.segments;
357
+ for (let segIdx = 0; segIdx < segments.length; segIdx++) {
358
+ const segment = segments[segIdx];
341
359
  if (segment.type === "equal") {
342
360
  for (let i = 0; i < segment.text.length; i++) {
343
361
  charStates[docAOffset + i] = { type: "equal" };
344
362
  }
345
363
  docAOffset += segment.text.length;
346
364
  } else if (segment.type === "delete") {
365
+ const nextSegment = segments[segIdx + 1];
366
+ const isReplacement = nextSegment && nextSegment.type === "insert";
367
+ const replacementId = isReplacement ? uuid.v4() : void 0;
347
368
  for (let i = 0; i < segment.text.length; i++) {
348
- charStates[docAOffset + i] = { type: "delete" };
369
+ charStates[docAOffset + i] = { type: "delete", replacementId };
349
370
  }
350
371
  docAOffset += segment.text.length;
372
+ if (isReplacement && nextSegment) {
373
+ insertions.push({
374
+ afterOffset: docAOffset,
375
+ text: nextSegment.text,
376
+ replacementId
377
+ });
378
+ segIdx++;
379
+ }
351
380
  } else if (segment.type === "insert") {
352
381
  insertions.push({
353
382
  afterOffset: docAOffset,
@@ -368,7 +397,7 @@ function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
368
397
  result.push({
369
398
  type: "text",
370
399
  text: ins.text,
371
- marks: [...node.marks || [], createTrackInsertMark(author)]
400
+ marks: [...node.marks || [], createTrackInsertMark(author, ins.replacementId)]
372
401
  });
373
402
  }
374
403
  const currentFormatChange = getFormatChangeAt(nodeOffset + i);
@@ -384,7 +413,7 @@ function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
384
413
  const chunk = text.substring(i, j);
385
414
  let marks = [...node.marks || []];
386
415
  if (charState.type === "delete") {
387
- marks.push(createTrackDeleteMark(author));
416
+ marks.push(createTrackDeleteMark(author, charState.replacementId));
388
417
  } else if (charState.type === "equal") {
389
418
  if (currentFormatChange) {
390
419
  const trackFormatMark = createTrackFormatMark(
@@ -408,7 +437,7 @@ function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
408
437
  result.push({
409
438
  type: "text",
410
439
  text: ins.text,
411
- marks: [...node.marks || [], createTrackInsertMark(author)]
440
+ marks: [...node.marks || [], createTrackInsertMark(author, ins.replacementId)]
412
441
  });
413
442
  }
414
443
  insertions = insertions.filter(
@@ -453,7 +482,7 @@ function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
453
482
  {
454
483
  type: "text",
455
484
  text: ins.text,
456
- marks: [createTrackInsertMark(author)]
485
+ marks: [createTrackInsertMark(author, ins.replacementId)]
457
486
  }
458
487
  ]
459
488
  }