@ansonlai/docx-redline-js 0.9.0 → 0.10.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ansonlai/docx-redline-js",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Host-independent OOXML reconciliation engine for .docx manipulation with track changes",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,7 +35,10 @@ const MARKDOWN_PATTERNS = [
35
35
  { regex: /\*\*\+\+(.+?)\+\+\*\*/, format: { bold: true, underline: true } },
36
36
  // Bold: **text** or __text__
37
37
  { regex: /\*\*(.+?)\*\*/, format: { bold: true } },
38
- { regex: /__(.+?)__/, format: { bold: true } },
38
+ // Underscore delimiters follow CommonMark flanking rules: not intraword, not part of a
39
+ // longer underscore run, and never around whitespace. So signature lines ("_____")
40
+ // and snake_case identifiers stay literal text.
41
+ { regex: /(?<![A-Za-z0-9_])__(?=[^_\s])(.+?)(?<=[^_\s])__(?![A-Za-z0-9_])/, format: { bold: true } },
39
42
  // Underline: ++text++
40
43
  { regex: /\+\+(.+?)\+\+/, format: { underline: true } },
41
44
  // Strikethrough: ~~text~~ or ~text~
@@ -43,7 +46,7 @@ const MARKDOWN_PATTERNS = [
43
46
  { regex: /~(.+?)~/, format: { strikethrough: true } },
44
47
  // Italic: *text* or _text_ (using lookahead only for compatibility)
45
48
  { regex: /\*(?!\*)(.+?)\*(?!\*)/, format: { italic: true } },
46
- { regex: /_(?!_)(.+?)_(?!_)/, format: { italic: true } }
49
+ { regex: /(?<![A-Za-z0-9_])_(?=[^_\s])(.+?)(?<=[^_\s])_(?![A-Za-z0-9_])/, format: { italic: true } }
47
50
  ];
48
51
 
49
52
  /**
@@ -32,7 +32,7 @@ export function applyCommentReplyToParts({ commentsXml, commentsExtendedXml = nu
32
32
  }
33
33
  const occupied = usedParaIds(commentsDoc, extendedDoc);
34
34
  // paraIds are unique across the whole package; body paragraphs can carry them too.
35
- if (documentXml) for (const match of String(documentXml).matchAll(/w14:paraId="([0-9A-Fa-f]{8})"/g)) occupied.add(match[1].toUpperCase());
35
+ if (documentXml) for (const match of String(documentXml).matchAll(/\bw14:paraId="([0-9A-Fa-f]{8})"/g)) occupied.add(match[1].toUpperCase());
36
36
  const parentParagraph = commentThreadParagraph(parent);
37
37
  if (!parentParagraph) return { status: 'error', error: { code: 'PARENT_COMMENT_INVALID', message: `Parent comment '${parentCommentId}' has no paragraph.` } };
38
38
  let parentParaId = commentParaId(parent);
@@ -258,6 +258,7 @@ export async function applyOperationToDocumentXml(documentXml, op, author, runti
258
258
  ...(operation.existingRevisions ? { existingRevisions: operation.existingRevisions } : {}),
259
259
  structuredContent: typeof operation.structuredContent === 'boolean' ? operation.structuredContent : (options.structuredContent !== false),
260
260
  explicitStructuredContent: operation.structuredContent === true,
261
+ plainTextContent: operation.structuredContent === false || (operation.structuredContent == null && options.structuredContent === false),
261
262
  ...(operation._localizedReplacementCompilation && operation.structuredContent !== true ? { literalTextEdit: true } : {}),
262
263
  pairReplacements: typeof operation.pairReplacements === 'boolean' ? operation.pairReplacements : (options.pairReplacements !== false),
263
264
  ...(operation.insertionAffinity ? { insertionAffinity: operation.insertionAffinity } : {}),
@@ -28,6 +28,7 @@ const SUPPORTED_OPERATION_TYPES = new Set([
28
28
  ]);
29
29
 
30
30
  export const EXISTING_REVISIONS_POLICIES = Object.freeze([
31
+ 'auto',
31
32
  'merge-same-author',
32
33
  'slice-cross-author',
33
34
  'reject-input',