ocean-brain 0.6.0 → 0.6.1

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.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/server/client/dist/assets/{Calendar-BytW4PeT.js → Calendar-BJHLksEZ.js} +1 -1
  3. package/server/client/dist/assets/{Callout-9sJgGNRb.js → Callout-wFx9oCas.js} +1 -1
  4. package/server/client/dist/assets/{Graph-o5u-NzrA.js → Graph-9piERaNR.js} +1 -1
  5. package/server/client/dist/assets/{Image-DxWhlIDG.js → Image-DK0lnaK2.js} +1 -1
  6. package/server/client/dist/assets/{Image.es-B0LL3pb7.js → Image.es-Be7par_j.js} +1 -1
  7. package/server/client/dist/assets/{Note-CYoYzZNu.js → Note-CC9ybxXL.js} +2 -2
  8. package/server/client/dist/assets/{Plus.es-DpxzgRtY.js → Plus.es-BKm7uDYu.js} +1 -1
  9. package/server/client/dist/assets/{Reminders-DAepTZg1.js → Reminders-DRxA8v98.js} +1 -1
  10. package/server/client/dist/assets/{Search-6KH7An44.js → Search-BunSQrqv.js} +1 -1
  11. package/server/client/dist/assets/{SurfaceCard-EMs50xSF.js → SurfaceCard-FhlC8VSR.js} +1 -1
  12. package/server/client/dist/assets/Tag-z_crJ5JP.js +1 -0
  13. package/server/client/dist/assets/{TagNotes-BTbu-f6v.js → TagNotes-D7wIJ4jy.js} +1 -1
  14. package/server/client/dist/assets/{Trash.es-C5x35NKF.js → Trash.es-ByMVwx0d.js} +1 -1
  15. package/server/client/dist/assets/{ViewNotes-DPEuki3y.js → ViewNotes-Duo9XmcJ.js} +1 -1
  16. package/server/client/dist/assets/{Views-BGkuNhVd.js → Views-D4Z_O9Kd.js} +1 -1
  17. package/server/client/dist/assets/{image.api-DRhRQ0Gf.js → image.api-B5Qi-Txv.js} +1 -1
  18. package/server/client/dist/assets/{index-DswSFFMb.js → index-cHJQCo8V.js} +1 -1
  19. package/server/client/dist/assets/{index-DYlYUrjH.js → index-nYj7BL3a.js} +40 -40
  20. package/server/client/dist/assets/{manage-image-detail-CJkfybR9.js → manage-image-detail-DcZggB1M.js} +1 -1
  21. package/server/client/dist/assets/manage-image-glbtBibn.js +1 -0
  22. package/server/client/dist/assets/{mcp-piouFDNm.js → mcp-BBUpQdS9.js} +1 -1
  23. package/server/client/dist/assets/{note-core-Z6kqulGB.js → note-core-DMZcZ4yV.js} +53 -53
  24. package/server/client/dist/assets/{note-vendor-i1M2FSI2.js → note-vendor-uuJO2MTD.js} +1 -1
  25. package/server/client/dist/assets/{placeholder-DGz3CHej.js → placeholder-B_qb_qkc.js} +1 -1
  26. package/server/client/dist/assets/{properties-CM4khczg.js → properties-CiyQv6Tb.js} +1 -1
  27. package/server/client/dist/assets/{trash-C2lItz-b.js → trash-CQnj4Rmv.js} +1 -1
  28. package/server/client/dist/assets/{useReminderMutate-DHjDDHKg.js → useReminderMutate-CSKliBcc.js} +1 -1
  29. package/server/client/dist/assets/{view-dashboard-C17WsdL7.js → view-dashboard-B5fKgvk_.js} +1 -1
  30. package/server/client/dist/index.html +3 -3
  31. package/server/dist/features/note/services/markdown-intent-write.js +17 -0
  32. package/server/dist/features/note/services/markdown-intent-write.js.map +1 -1
  33. package/server/dist/features/note/services/markdown-patch.js.map +1 -1
  34. package/server/dist/modules/blocknote.js +320 -5
  35. package/server/dist/modules/blocknote.js.map +1 -1
  36. package/server/client/dist/assets/Tag-C89j8x56.js +0 -1
  37. package/server/client/dist/assets/manage-image-C6sHhWnI.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/features/note/services/markdown-patch.ts"],"sourcesContent":["import crypto from 'crypto';\n\nconst HASH_ALGORITHM = 'sha256';\nconst EXCERPT_CONTEXT_CHARS = 80;\nconst DIFF_CONTEXT_LINES = 3;\n\nexport interface MarkdownPatchNoteSnapshot {\n id: string;\n title: string;\n updatedAt: string;\n markdown: string;\n}\n\nexport interface ExactTextMarkdownPatchSelector {\n type: 'exact_text';\n text: string;\n before?: string;\n after?: string;\n}\n\nexport interface MatchCandidateMarkdownPatchSelector {\n type: 'match_candidate';\n text: string;\n matchIndex: number;\n lineStart: number;\n matchSha256: string;\n surroundingHash: string;\n positionHint?: 'first' | 'last';\n}\n\nexport type MarkdownPatchSelector = ExactTextMarkdownPatchSelector | MatchCandidateMarkdownPatchSelector;\n\nexport interface ReplaceMarkdownPatchOperation {\n type: 'replace';\n replacement: string;\n}\n\nexport interface InsertBeforeMarkdownPatchOperation {\n type: 'insert_before';\n insertion: string;\n}\n\nexport interface InsertAfterMarkdownPatchOperation {\n type: 'insert_after';\n insertion: string;\n}\n\nexport type MarkdownPatchOperation =\n | ReplaceMarkdownPatchOperation\n | InsertBeforeMarkdownPatchOperation\n | InsertAfterMarkdownPatchOperation;\n\nexport interface MarkdownChangePolicy {\n allowNoop?: boolean;\n maxChangedChars?: number;\n maxChangedLines?: number;\n preserveReferences?: boolean | 'warn';\n preserveTags?: boolean | 'warn';\n}\n\nexport interface PreviewMarkdownPatchInput {\n note: MarkdownPatchNoteSnapshot;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n selector: MarkdownPatchSelector;\n operation: MarkdownPatchOperation;\n policy?: MarkdownChangePolicy;\n}\n\nexport interface MarkdownAppendPlacementEnd {\n type: 'end';\n}\n\nexport interface MarkdownAppendPlacementAfterHeading {\n type: 'after_heading';\n heading: string;\n level?: number;\n}\n\nexport type MarkdownAppendPlacement = MarkdownAppendPlacementEnd | MarkdownAppendPlacementAfterHeading;\n\nexport interface PreviewMarkdownAppendInput {\n note: MarkdownPatchNoteSnapshot;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n insertion: string;\n placement?: MarkdownAppendPlacement;\n separator?: '\\n\\n' | '\\n';\n policy?: MarkdownChangePolicy;\n}\n\nexport interface PreviewMarkdownReplaceInput {\n note: MarkdownPatchNoteSnapshot;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n replacement: string;\n policy?: MarkdownChangePolicy;\n}\n\nexport interface MarkdownPatchMatch {\n matchIndex: number;\n lineStart: number;\n lineEnd: number;\n text: string;\n beforeExcerpt?: string;\n afterExcerpt?: string;\n matchSha256: string;\n surroundingHash: string;\n positionHint?: 'first' | 'last';\n}\n\nexport interface MarkdownChangeDryRun {\n status: 'dry_run';\n note: {\n id: string;\n title: string;\n updatedAt: string;\n };\n match?: {\n count: 1;\n lineStart: number;\n lineEnd: number;\n selectorType: string;\n matchedTextSha256: string;\n surroundingHash: string;\n };\n placement?: MarkdownAppendPlacement;\n proposed: {\n changedLineCount: number;\n changedCharCount: number;\n beforeMarkdownSha256: string;\n afterMarkdownSha256: string;\n diff: string;\n };\n warnings: string[];\n}\n\nexport interface MarkdownChangePlan extends MarkdownChangeDryRun {\n afterMarkdown: string;\n}\n\nexport interface MarkdownPatchNeedsDisambiguation {\n status: 'needs_disambiguation';\n reason: 'TARGET_AMBIGUOUS';\n matches: MarkdownPatchMatch[];\n}\n\nexport interface MarkdownChangeFailure {\n status: 'failed';\n reason:\n | 'ANCHOR_MISMATCH'\n | 'BASELINE_MISMATCH'\n | 'CANDIDATE_MISMATCH'\n | 'CHANGE_LIMIT_EXCEEDED'\n | 'EMPTY_INSERTION'\n | 'EMPTY_REPLACEMENT'\n | 'EMPTY_TARGET'\n | 'HEADING_AMBIGUOUS'\n | 'HEADING_NOT_FOUND'\n | 'INVALID_HEADING_LEVEL'\n | 'INVALID_PROPERTY_INPUT'\n | 'MISSING_BASELINE'\n | 'NOOP'\n | 'REFERENCE_STRUCTURE_DECREASED'\n | 'REFERENCE_TOKEN_DECREASED'\n | 'TAG_TOKEN_DECREASED'\n | 'TARGET_NOT_FOUND'\n | 'UNSUPPORTED_MARKDOWN_STRUCTURE';\n message: string;\n}\n\nexport type MarkdownPatchPreviewResult =\n | MarkdownChangeDryRun\n | MarkdownPatchNeedsDisambiguation\n | MarkdownChangeFailure;\n\nexport type MarkdownPatchPlanResult = MarkdownChangePlan | MarkdownPatchNeedsDisambiguation | MarkdownChangeFailure;\nexport type MarkdownAppendPlanResult = MarkdownChangePlan | MarkdownChangeFailure;\nexport type MarkdownReplacePlanResult = MarkdownChangePlan | MarkdownChangeFailure;\n\ninterface RawTextMatch {\n matchIndex: number;\n start: number;\n end: number;\n text: string;\n}\n\ninterface HeadingMatch {\n heading: string;\n level: number;\n lineIndex: number;\n start: number;\n nextSectionStart: number;\n}\n\nexport const calculateMarkdownSha256 = (value: string) => {\n return crypto.createHash(HASH_ALGORITHM).update(value, 'utf8').digest('hex');\n};\n\nconst countNewlines = (value: string) => {\n let count = 0;\n\n for (const character of value) {\n if (character === '\\n') {\n count += 1;\n }\n }\n\n return count;\n};\n\nconst getLineRange = (markdown: string, match: RawTextMatch) => {\n const lineStart = countNewlines(markdown.slice(0, match.start)) + 1;\n const lineEnd = lineStart + countNewlines(match.text);\n\n return {\n lineStart,\n lineEnd,\n };\n};\n\nconst buildExcerpt = (markdown: string, start: number, end: number) => {\n const excerpt = markdown.slice(start, end).trim();\n\n return excerpt.length > 0 ? excerpt : undefined;\n};\n\nconst toPatchMatch = (markdown: string, match: RawTextMatch, totalMatches: number): MarkdownPatchMatch => {\n const { lineStart, lineEnd } = getLineRange(markdown, match);\n const beforeStart = Math.max(0, match.start - EXCERPT_CONTEXT_CHARS);\n const afterEnd = Math.min(markdown.length, match.end + EXCERPT_CONTEXT_CHARS);\n const beforeText = markdown.slice(beforeStart, match.start);\n const afterText = markdown.slice(match.end, afterEnd);\n\n return {\n matchIndex: match.matchIndex,\n lineStart,\n lineEnd,\n text: match.text,\n beforeExcerpt: buildExcerpt(markdown, beforeStart, match.start),\n afterExcerpt: buildExcerpt(markdown, match.end, afterEnd),\n matchSha256: calculateMarkdownSha256(match.text),\n surroundingHash: calculateMarkdownSha256(JSON.stringify({ beforeText, targetText: match.text, afterText })),\n ...(match.matchIndex === 0 && totalMatches > 1 ? { positionHint: 'first' } : {}),\n ...(match.matchIndex === totalMatches - 1 && totalMatches > 1 ? { positionHint: 'last' } : {}),\n };\n};\n\nconst findExactTextMatches = (markdown: string, text: string) => {\n const matches: RawTextMatch[] = [];\n let searchStart = 0;\n\n while (searchStart <= markdown.length) {\n const start = markdown.indexOf(text, searchStart);\n\n if (start === -1) {\n break;\n }\n\n matches.push({\n matchIndex: matches.length,\n start,\n end: start + text.length,\n text,\n });\n searchStart = start + text.length;\n }\n\n return matches;\n};\n\nconst splitLines = (value: string) => {\n return value.split('\\n');\n};\n\nconst findSharedLineEdges = (beforeLines: string[], afterLines: string[]) => {\n let prefix = 0;\n const maxPrefix = Math.min(beforeLines.length, afterLines.length);\n\n while (prefix < maxPrefix && beforeLines[prefix] === afterLines[prefix]) {\n prefix += 1;\n }\n\n let suffix = 0;\n const maxSuffix = Math.min(beforeLines.length - prefix, afterLines.length - prefix);\n\n while (\n suffix < maxSuffix &&\n beforeLines[beforeLines.length - 1 - suffix] === afterLines[afterLines.length - 1 - suffix]\n ) {\n suffix += 1;\n }\n\n return {\n prefix,\n suffix,\n };\n};\n\nconst formatDiffRange = (lineIndex: number, lineCount: number) => {\n const lineNumber = lineIndex + 1;\n\n return lineCount === 1 ? String(lineNumber) : `${lineNumber},${lineCount}`;\n};\n\nexport const createUnifiedMarkdownDiff = (\n beforeMarkdown: string,\n afterMarkdown: string,\n contextLines: number | null = DIFF_CONTEXT_LINES,\n) => {\n const beforeLines = splitLines(beforeMarkdown);\n const afterLines = splitLines(afterMarkdown);\n const { prefix, suffix } = findSharedLineEdges(beforeLines, afterLines);\n const changedBeforeStart = prefix;\n const changedBeforeEnd = beforeLines.length - suffix;\n const changedAfterStart = prefix;\n const changedAfterEnd = afterLines.length - suffix;\n const displayBeforeStart = contextLines === null ? 0 : Math.max(0, changedBeforeStart - contextLines);\n const displayBeforeEnd =\n contextLines === null ? beforeLines.length : Math.min(beforeLines.length, changedBeforeEnd + contextLines);\n const displayAfterStart = contextLines === null ? 0 : Math.max(0, changedAfterStart - contextLines);\n const displayAfterEnd =\n contextLines === null ? afterLines.length : Math.min(afterLines.length, changedAfterEnd + contextLines);\n const diffLines = [\n '--- before.md',\n '+++ after.md',\n `@@ -${formatDiffRange(displayBeforeStart, displayBeforeEnd - displayBeforeStart)} +${formatDiffRange(displayAfterStart, displayAfterEnd - displayAfterStart)} @@`,\n ];\n\n for (let index = displayBeforeStart; index < changedBeforeStart; index += 1) {\n diffLines.push(` ${beforeLines[index]}`);\n }\n\n for (let index = changedBeforeStart; index < changedBeforeEnd; index += 1) {\n diffLines.push(`-${beforeLines[index]}`);\n }\n\n for (let index = changedAfterStart; index < changedAfterEnd; index += 1) {\n diffLines.push(`+${afterLines[index]}`);\n }\n\n for (let index = changedBeforeEnd; index < displayBeforeEnd; index += 1) {\n diffLines.push(` ${beforeLines[index]}`);\n }\n\n return diffLines.join('\\n');\n};\n\nconst countChangedLines = (beforeMarkdown: string, afterMarkdown: string) => {\n const beforeLines = splitLines(beforeMarkdown);\n const afterLines = splitLines(afterMarkdown);\n const { prefix, suffix } = findSharedLineEdges(beforeLines, afterLines);\n const removedLineCount = beforeLines.length - prefix - suffix;\n const addedLineCount = afterLines.length - prefix - suffix;\n\n return Math.max(removedLineCount, addedLineCount);\n};\n\nconst isMarkdownTokenWhitespace = (character: string) => /\\s/.test(character);\n\nexport const countExplicitTagTokens = (value: string) => {\n let count = 0;\n\n for (let index = 0; index < value.length; index += 1) {\n if (value[index] !== '[' || (value[index + 1] !== '@' && value[index + 1] !== '#')) {\n continue;\n }\n\n let cursor = index + 2;\n let isValid = cursor < value.length;\n\n while (cursor < value.length && value[cursor] !== ']') {\n if (value[cursor] === '[' || isMarkdownTokenWhitespace(value[cursor])) {\n isValid = false;\n break;\n }\n\n cursor += 1;\n }\n\n if (isValid && cursor < value.length && cursor > index + 2) {\n count += 1;\n index = cursor;\n continue;\n }\n\n if (!isValid) {\n index = Math.max(index, cursor - 1);\n }\n }\n\n return count;\n};\n\nexport const countMarkdownReferenceTokens = (value: string) => {\n let count = 0;\n let cursor = 0;\n\n while (cursor < value.length) {\n const start = value.indexOf('[[', cursor);\n\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf(']]', start + 2);\n\n if (end === -1) {\n break;\n }\n\n if (end > start + 2) {\n count += 1;\n }\n\n cursor = end + 2;\n }\n\n return count;\n};\n\nconst parseVersionTimestamp = (value: string) => {\n const timestamp = /^\\d+$/.test(value) ? Number(value) : Date.parse(value);\n\n return Number.isFinite(timestamp) ? timestamp : null;\n};\n\nconst noteVersionsMatch = (expectedUpdatedAt: string, currentUpdatedAt: string) => {\n const expectedTimestamp = parseVersionTimestamp(expectedUpdatedAt);\n const currentTimestamp = parseVersionTimestamp(currentUpdatedAt);\n\n return expectedTimestamp !== null && currentTimestamp !== null && expectedTimestamp === currentTimestamp;\n};\n\nconst getPreservationFailure = (\n beforeMarkdown: string,\n afterMarkdown: string,\n policy: MarkdownChangePolicy | undefined,\n): MarkdownChangeFailure | null => {\n const beforeTagCount = countExplicitTagTokens(beforeMarkdown);\n const afterTagCount = countExplicitTagTokens(afterMarkdown);\n\n if (policy?.preserveTags === true && afterTagCount < beforeTagCount) {\n return {\n status: 'failed',\n reason: 'TAG_TOKEN_DECREASED',\n message: 'The patch would reduce explicit tag tokens.',\n };\n }\n\n const beforeReferenceCount = countMarkdownReferenceTokens(beforeMarkdown);\n const afterReferenceCount = countMarkdownReferenceTokens(afterMarkdown);\n\n if (policy?.preserveReferences === true && afterReferenceCount < beforeReferenceCount) {\n return {\n status: 'failed',\n reason: 'REFERENCE_TOKEN_DECREASED',\n message: 'The patch would reduce note reference tokens.',\n };\n }\n\n return null;\n};\n\nconst collectWarnings = (\n beforeMarkdown: string,\n afterMarkdown: string,\n policy: MarkdownChangePolicy | undefined,\n): string[] => {\n const warnings: string[] = [];\n const beforeTagCount = countExplicitTagTokens(beforeMarkdown);\n const afterTagCount = countExplicitTagTokens(afterMarkdown);\n const shouldWarnTags = policy?.preserveTags === undefined || policy.preserveTags === 'warn';\n\n if (shouldWarnTags && afterTagCount < beforeTagCount) {\n warnings.push('TAG_TOKEN_COUNT_DECREASED');\n }\n\n const beforeReferenceCount = countMarkdownReferenceTokens(beforeMarkdown);\n const afterReferenceCount = countMarkdownReferenceTokens(afterMarkdown);\n const shouldWarnReferences = policy?.preserveReferences === undefined || policy.preserveReferences === 'warn';\n\n if (shouldWarnReferences && afterReferenceCount < beforeReferenceCount) {\n warnings.push('REFERENCE_TOKEN_COUNT_DECREASED');\n }\n\n return warnings;\n};\n\nconst validateBaseline = (\n note: MarkdownPatchNoteSnapshot,\n expectedUpdatedAt: string | undefined,\n baseMarkdownSha256: string | undefined,\n): MarkdownChangeFailure | null => {\n const beforeMarkdownSha256 = calculateMarkdownSha256(note.markdown);\n\n if (!expectedUpdatedAt && !baseMarkdownSha256) {\n return {\n status: 'failed',\n reason: 'MISSING_BASELINE',\n message: 'expectedUpdatedAt or baseMarkdownSha256 is required for markdown writes.',\n };\n }\n\n if (\n (expectedUpdatedAt && !noteVersionsMatch(expectedUpdatedAt, note.updatedAt)) ||\n (baseMarkdownSha256 && baseMarkdownSha256 !== beforeMarkdownSha256)\n ) {\n return {\n status: 'failed',\n reason: 'BASELINE_MISMATCH',\n message: 'The markdown write baseline does not match the current note.',\n };\n }\n\n return null;\n};\n\nconst validateChangeLimits = (\n beforeMarkdown: string,\n afterMarkdown: string,\n changedCharCount: number,\n policy: MarkdownChangePolicy | undefined,\n): MarkdownChangeFailure | null => {\n const changedLineCount = countChangedLines(beforeMarkdown, afterMarkdown);\n\n if (\n (policy?.maxChangedLines !== undefined && changedLineCount > policy.maxChangedLines) ||\n (policy?.maxChangedChars !== undefined && changedCharCount > policy.maxChangedChars)\n ) {\n return {\n status: 'failed',\n reason: 'CHANGE_LIMIT_EXCEEDED',\n message: 'The markdown write exceeds the configured change limit.',\n };\n }\n\n return null;\n};\n\nconst createChangePlan = ({\n note,\n afterMarkdown,\n changedCharCount,\n policy,\n diffContextLines = DIFF_CONTEXT_LINES,\n match,\n placement,\n}: {\n note: MarkdownPatchNoteSnapshot;\n afterMarkdown: string;\n changedCharCount: number;\n policy: MarkdownChangePolicy | undefined;\n diffContextLines?: number | null;\n match?: MarkdownChangeDryRun['match'];\n placement?: MarkdownAppendPlacement;\n}): MarkdownChangePlan | MarkdownChangeFailure => {\n if (!policy?.allowNoop && afterMarkdown === note.markdown) {\n return {\n status: 'failed',\n reason: 'NOOP',\n message: 'The markdown write would not change the note.',\n };\n }\n\n const preservationFailure = getPreservationFailure(note.markdown, afterMarkdown, policy);\n\n if (preservationFailure) {\n return preservationFailure;\n }\n\n const limitFailure = validateChangeLimits(note.markdown, afterMarkdown, changedCharCount, policy);\n\n if (limitFailure) {\n return limitFailure;\n }\n\n return {\n status: 'dry_run',\n note: {\n id: note.id,\n title: note.title,\n updatedAt: note.updatedAt,\n },\n ...(match ? { match } : {}),\n ...(placement ? { placement } : {}),\n proposed: {\n changedLineCount: countChangedLines(note.markdown, afterMarkdown),\n changedCharCount,\n beforeMarkdownSha256: calculateMarkdownSha256(note.markdown),\n afterMarkdownSha256: calculateMarkdownSha256(afterMarkdown),\n diff: createUnifiedMarkdownDiff(note.markdown, afterMarkdown, diffContextLines),\n },\n warnings: collectWarnings(note.markdown, afterMarkdown, policy),\n afterMarkdown,\n };\n};\n\nconst matchHasAnchors = (markdown: string, match: RawTextMatch, selector: ExactTextMarkdownPatchSelector) => {\n if (selector.before !== undefined && !markdown.slice(0, match.start).endsWith(selector.before)) {\n return false;\n }\n\n if (selector.after !== undefined && !markdown.slice(match.end).startsWith(selector.after)) {\n return false;\n }\n\n return true;\n};\n\nconst selectExactTextMatch = (\n markdown: string,\n selector: ExactTextMarkdownPatchSelector,\n):\n | { match: RawTextMatch; patchMatch: MarkdownPatchMatch }\n | MarkdownPatchNeedsDisambiguation\n | MarkdownChangeFailure => {\n if (selector.text.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_TARGET',\n message: 'Exact text selector must not be empty.',\n };\n }\n\n const rawMatches = findExactTextMatches(markdown, selector.text);\n\n if (rawMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'No exact text match was found in the current note.',\n };\n }\n\n const anchoredMatches = rawMatches.filter((match) => matchHasAnchors(markdown, match, selector));\n\n if (anchoredMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'ANCHOR_MISMATCH',\n message: 'Exact text matches were found, but before/after anchors did not match.',\n };\n }\n\n if (anchoredMatches.length > 1) {\n return {\n status: 'needs_disambiguation',\n reason: 'TARGET_AMBIGUOUS',\n matches: anchoredMatches.map((match) => toPatchMatch(markdown, match, rawMatches.length)),\n };\n }\n\n const match = anchoredMatches[0];\n\n return {\n match,\n patchMatch: toPatchMatch(markdown, match, rawMatches.length),\n };\n};\n\nconst selectMatchCandidate = (\n markdown: string,\n selector: MatchCandidateMarkdownPatchSelector,\n): { match: RawTextMatch; patchMatch: MarkdownPatchMatch } | MarkdownChangeFailure => {\n if (selector.text.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_TARGET',\n message: 'Match candidate selector text must not be empty.',\n };\n }\n\n const rawMatches = findExactTextMatches(markdown, selector.text);\n\n if (rawMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'No match candidate text was found in the current note.',\n };\n }\n\n const match = rawMatches.find((candidate) => candidate.matchIndex === selector.matchIndex);\n\n if (!match) {\n return {\n status: 'failed',\n reason: 'CANDIDATE_MISMATCH',\n message: 'The selected match index does not exist in the current note.',\n };\n }\n\n const patchMatch = toPatchMatch(markdown, match, rawMatches.length);\n const positionMatches = selector.positionHint === undefined || patchMatch.positionHint === selector.positionHint;\n\n if (\n patchMatch.lineStart !== selector.lineStart ||\n patchMatch.matchSha256 !== selector.matchSha256 ||\n patchMatch.surroundingHash !== selector.surroundingHash ||\n !positionMatches\n ) {\n return {\n status: 'failed',\n reason: 'CANDIDATE_MISMATCH',\n message: 'The selected match candidate no longer matches the current note context.',\n };\n }\n\n return {\n match,\n patchMatch,\n };\n};\n\nconst applyPatchOperation = (markdown: string, match: RawTextMatch, operation: MarkdownPatchOperation) => {\n if (operation.type === 'replace') {\n return {\n markdown: `${markdown.slice(0, match.start)}${operation.replacement}${markdown.slice(match.end)}`,\n changedCharCount: match.text.length + operation.replacement.length,\n };\n }\n\n if (operation.type === 'insert_before') {\n return {\n markdown: `${markdown.slice(0, match.start)}${operation.insertion}${markdown.slice(match.start)}`,\n changedCharCount: operation.insertion.length,\n };\n }\n\n return {\n markdown: `${markdown.slice(0, match.end)}${operation.insertion}${markdown.slice(match.end)}`,\n changedCharCount: operation.insertion.length,\n };\n};\n\nexport const buildMarkdownPatchPlan = (input: PreviewMarkdownPatchInput): MarkdownPatchPlanResult => {\n const baselineFailure = validateBaseline(input.note, input.expectedUpdatedAt, input.baseMarkdownSha256);\n\n if (baselineFailure) {\n return baselineFailure;\n }\n\n const selected =\n input.selector.type === 'exact_text'\n ? selectExactTextMatch(input.note.markdown, input.selector)\n : selectMatchCandidate(input.note.markdown, input.selector);\n\n if ('status' in selected) {\n return selected;\n }\n\n const patched = applyPatchOperation(input.note.markdown, selected.match, input.operation);\n const plan = createChangePlan({\n note: input.note,\n afterMarkdown: patched.markdown,\n changedCharCount: patched.changedCharCount,\n policy: input.policy,\n match: {\n count: 1,\n lineStart: selected.patchMatch.lineStart,\n lineEnd: selected.patchMatch.lineEnd,\n selectorType: input.selector.type,\n matchedTextSha256: selected.patchMatch.matchSha256,\n surroundingHash: selected.patchMatch.surroundingHash,\n },\n });\n\n return plan;\n};\n\nconst parseHeadingLine = (line: string) => {\n const match = /^(#{1,6})\\s+(.+?)\\s*#*\\s*$/.exec(line);\n\n if (!match) {\n return null;\n }\n\n return {\n level: match[1].length,\n heading: match[2].trim(),\n };\n};\n\nconst getLineStartOffsets = (lines: string[]) => {\n const offsets: number[] = [];\n let offset = 0;\n\n for (const line of lines) {\n offsets.push(offset);\n offset += line.length + 1;\n }\n\n return offsets;\n};\n\nconst findHeadingMatches = (markdown: string, placement: MarkdownAppendPlacementAfterHeading) => {\n const lines = splitLines(markdown);\n const offsets = getLineStartOffsets(lines);\n const headingLines = lines\n .map((line, index) => {\n const heading = parseHeadingLine(line);\n\n if (!heading) {\n return null;\n }\n\n return {\n ...heading,\n lineIndex: index,\n start: offsets[index],\n };\n })\n .filter((heading): heading is Omit<HeadingMatch, 'nextSectionStart'> => heading !== null);\n const matches = headingLines.filter((heading) => {\n return (\n heading.heading === placement.heading &&\n (placement.level === undefined || heading.level === placement.level)\n );\n });\n\n return matches.map((match) => {\n const nextHeading = headingLines.find(\n (heading) => heading.lineIndex > match.lineIndex && heading.level <= match.level,\n );\n\n return {\n ...match,\n nextSectionStart: nextHeading?.start ?? markdown.length,\n };\n });\n};\n\nconst appendWithSeparator = (prefix: string, insertion: string, separator: '\\n\\n' | '\\n') => {\n if (prefix.length === 0) {\n return insertion;\n }\n\n return `${prefix}${prefix.endsWith(separator) ? '' : separator}${insertion}`;\n};\n\nconst applyAppendPlacement = (\n markdown: string,\n insertion: string,\n placement: MarkdownAppendPlacement,\n separator: '\\n\\n' | '\\n',\n): { markdown: string; placement: MarkdownAppendPlacement } | MarkdownChangeFailure => {\n if (insertion.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_INSERTION',\n message: 'Append insertion must not be empty.',\n };\n }\n\n if (placement.type === 'end') {\n return {\n markdown: appendWithSeparator(markdown, insertion, separator),\n placement,\n };\n }\n\n if (\n placement.level !== undefined &&\n (!Number.isInteger(placement.level) || placement.level < 1 || placement.level > 6)\n ) {\n return {\n status: 'failed',\n reason: 'INVALID_HEADING_LEVEL',\n message: 'Heading level must be an integer from 1 to 6.',\n };\n }\n\n const headingMatches = findHeadingMatches(markdown, placement);\n\n if (headingMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'HEADING_NOT_FOUND',\n message: 'The requested heading was not found.',\n };\n }\n\n if (headingMatches.length > 1) {\n return {\n status: 'failed',\n reason: 'HEADING_AMBIGUOUS',\n message: 'The requested heading appears more than once.',\n };\n }\n\n const [headingMatch] = headingMatches;\n const prefix = markdown.slice(0, headingMatch.nextSectionStart);\n const suffix = markdown.slice(headingMatch.nextSectionStart);\n const prefixWithInsertion = appendWithSeparator(prefix, insertion, separator);\n const nextMarkdown =\n suffix.length === 0\n ? prefixWithInsertion\n : `${prefixWithInsertion}${prefixWithInsertion.endsWith(separator) ? '' : separator}${suffix}`;\n\n return {\n markdown: nextMarkdown,\n placement,\n };\n};\n\nexport const buildMarkdownAppendPlan = (input: PreviewMarkdownAppendInput): MarkdownAppendPlanResult => {\n const baselineFailure = validateBaseline(input.note, input.expectedUpdatedAt, input.baseMarkdownSha256);\n\n if (baselineFailure) {\n return baselineFailure;\n }\n\n const placement = input.placement ?? { type: 'end' as const };\n const separator = input.separator ?? '\\n\\n';\n const appended = applyAppendPlacement(input.note.markdown, input.insertion, placement, separator);\n\n if ('status' in appended) {\n return appended;\n }\n\n return createChangePlan({\n note: input.note,\n afterMarkdown: appended.markdown,\n changedCharCount: input.insertion.length,\n policy: input.policy,\n placement: appended.placement,\n });\n};\n\nexport const buildMarkdownReplacePlan = (input: PreviewMarkdownReplaceInput): MarkdownReplacePlanResult => {\n const baselineFailure = validateBaseline(input.note, input.expectedUpdatedAt, input.baseMarkdownSha256);\n\n if (baselineFailure) {\n return baselineFailure;\n }\n\n if (input.replacement.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_REPLACEMENT',\n message: 'Replacement markdown must not be empty.',\n };\n }\n\n return createChangePlan({\n note: input.note,\n afterMarkdown: input.replacement,\n changedCharCount: input.note.markdown.length + input.replacement.length,\n policy: input.policy,\n diffContextLines: null,\n });\n};\n\nconst toPreviewResult = (plan: MarkdownChangePlan): MarkdownChangeDryRun => {\n return {\n status: 'dry_run',\n note: plan.note,\n ...(plan.match ? { match: plan.match } : {}),\n ...(plan.placement ? { placement: plan.placement } : {}),\n proposed: plan.proposed,\n warnings: plan.warnings,\n };\n};\n\nexport const previewMarkdownPatch = (input: PreviewMarkdownPatchInput): MarkdownPatchPreviewResult => {\n const plan = buildMarkdownPatchPlan(input);\n\n if (plan.status !== 'dry_run') {\n return plan;\n }\n\n return toPreviewResult(plan);\n};\n\nexport const previewMarkdownAppend = (\n input: PreviewMarkdownAppendInput,\n): MarkdownChangeDryRun | MarkdownChangeFailure => {\n const plan = buildMarkdownAppendPlan(input);\n\n if (plan.status !== 'dry_run') {\n return plan;\n }\n\n return toPreviewResult(plan);\n};\n\nexport const previewMarkdownReplace = (\n input: PreviewMarkdownReplaceInput,\n): MarkdownChangeDryRun | MarkdownChangeFailure => {\n const plan = buildMarkdownReplacePlan(input);\n\n if (plan.status !== 'dry_run') {\n return plan;\n }\n\n return toPreviewResult(plan);\n};\n"],"mappings":"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","names":["match"]}
1
+ {"version":3,"sources":["../../../../src/features/note/services/markdown-patch.ts"],"sourcesContent":["import crypto from 'crypto';\n\nconst HASH_ALGORITHM = 'sha256';\nconst EXCERPT_CONTEXT_CHARS = 80;\nconst DIFF_CONTEXT_LINES = 3;\n\nexport interface MarkdownPatchNoteSnapshot {\n id: string;\n title: string;\n updatedAt: string;\n markdown: string;\n}\n\nexport interface ExactTextMarkdownPatchSelector {\n type: 'exact_text';\n text: string;\n before?: string;\n after?: string;\n}\n\nexport interface MatchCandidateMarkdownPatchSelector {\n type: 'match_candidate';\n text: string;\n matchIndex: number;\n lineStart: number;\n matchSha256: string;\n surroundingHash: string;\n positionHint?: 'first' | 'last';\n}\n\nexport type MarkdownPatchSelector = ExactTextMarkdownPatchSelector | MatchCandidateMarkdownPatchSelector;\n\nexport interface ReplaceMarkdownPatchOperation {\n type: 'replace';\n replacement: string;\n}\n\nexport interface InsertBeforeMarkdownPatchOperation {\n type: 'insert_before';\n insertion: string;\n}\n\nexport interface InsertAfterMarkdownPatchOperation {\n type: 'insert_after';\n insertion: string;\n}\n\nexport type MarkdownPatchOperation =\n | ReplaceMarkdownPatchOperation\n | InsertBeforeMarkdownPatchOperation\n | InsertAfterMarkdownPatchOperation;\n\nexport interface MarkdownChangePolicy {\n allowNoop?: boolean;\n maxChangedChars?: number;\n maxChangedLines?: number;\n preserveReferences?: boolean | 'warn';\n preserveTags?: boolean | 'warn';\n}\n\nexport interface PreviewMarkdownPatchInput {\n note: MarkdownPatchNoteSnapshot;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n selector: MarkdownPatchSelector;\n operation: MarkdownPatchOperation;\n policy?: MarkdownChangePolicy;\n}\n\nexport interface MarkdownAppendPlacementEnd {\n type: 'end';\n}\n\nexport interface MarkdownAppendPlacementAfterHeading {\n type: 'after_heading';\n heading: string;\n level?: number;\n}\n\nexport type MarkdownAppendPlacement = MarkdownAppendPlacementEnd | MarkdownAppendPlacementAfterHeading;\n\nexport interface PreviewMarkdownAppendInput {\n note: MarkdownPatchNoteSnapshot;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n insertion: string;\n placement?: MarkdownAppendPlacement;\n separator?: '\\n\\n' | '\\n';\n policy?: MarkdownChangePolicy;\n}\n\nexport interface PreviewMarkdownReplaceInput {\n note: MarkdownPatchNoteSnapshot;\n expectedUpdatedAt?: string;\n baseMarkdownSha256?: string;\n intent: string;\n replacement: string;\n policy?: MarkdownChangePolicy;\n}\n\nexport interface MarkdownPatchMatch {\n matchIndex: number;\n lineStart: number;\n lineEnd: number;\n text: string;\n beforeExcerpt?: string;\n afterExcerpt?: string;\n matchSha256: string;\n surroundingHash: string;\n positionHint?: 'first' | 'last';\n}\n\nexport interface MarkdownChangeDryRun {\n status: 'dry_run';\n note: {\n id: string;\n title: string;\n updatedAt: string;\n };\n match?: {\n count: 1;\n lineStart: number;\n lineEnd: number;\n selectorType: string;\n matchedTextSha256: string;\n surroundingHash: string;\n };\n placement?: MarkdownAppendPlacement;\n proposed: {\n changedLineCount: number;\n changedCharCount: number;\n beforeMarkdownSha256: string;\n afterMarkdownSha256: string;\n diff: string;\n };\n warnings: string[];\n}\n\nexport interface MarkdownChangePlan extends MarkdownChangeDryRun {\n afterMarkdown: string;\n}\n\nexport interface MarkdownPatchNeedsDisambiguation {\n status: 'needs_disambiguation';\n reason: 'TARGET_AMBIGUOUS';\n matches: MarkdownPatchMatch[];\n}\n\nexport interface MarkdownChangeFailure {\n status: 'failed';\n reason:\n | 'ANCHOR_MISMATCH'\n | 'BASELINE_MISMATCH'\n | 'CANDIDATE_MISMATCH'\n | 'CHANGE_LIMIT_EXCEEDED'\n | 'EMPTY_INSERTION'\n | 'EMPTY_REPLACEMENT'\n | 'EMPTY_TARGET'\n | 'HEADING_AMBIGUOUS'\n | 'HEADING_NOT_FOUND'\n | 'INVALID_HEADING_LEVEL'\n | 'INVALID_PROPERTY_INPUT'\n | 'MARKDOWN_IMPORT_LOSSY'\n | 'MISSING_BASELINE'\n | 'NOOP'\n | 'REFERENCE_STRUCTURE_DECREASED'\n | 'REFERENCE_TOKEN_DECREASED'\n | 'TAG_TOKEN_DECREASED'\n | 'TARGET_NOT_FOUND'\n | 'UNSUPPORTED_MARKDOWN_STRUCTURE';\n message: string;\n}\n\nexport type MarkdownPatchPreviewResult =\n | MarkdownChangeDryRun\n | MarkdownPatchNeedsDisambiguation\n | MarkdownChangeFailure;\n\nexport type MarkdownPatchPlanResult = MarkdownChangePlan | MarkdownPatchNeedsDisambiguation | MarkdownChangeFailure;\nexport type MarkdownAppendPlanResult = MarkdownChangePlan | MarkdownChangeFailure;\nexport type MarkdownReplacePlanResult = MarkdownChangePlan | MarkdownChangeFailure;\n\ninterface RawTextMatch {\n matchIndex: number;\n start: number;\n end: number;\n text: string;\n}\n\ninterface HeadingMatch {\n heading: string;\n level: number;\n lineIndex: number;\n start: number;\n nextSectionStart: number;\n}\n\nexport const calculateMarkdownSha256 = (value: string) => {\n return crypto.createHash(HASH_ALGORITHM).update(value, 'utf8').digest('hex');\n};\n\nconst countNewlines = (value: string) => {\n let count = 0;\n\n for (const character of value) {\n if (character === '\\n') {\n count += 1;\n }\n }\n\n return count;\n};\n\nconst getLineRange = (markdown: string, match: RawTextMatch) => {\n const lineStart = countNewlines(markdown.slice(0, match.start)) + 1;\n const lineEnd = lineStart + countNewlines(match.text);\n\n return {\n lineStart,\n lineEnd,\n };\n};\n\nconst buildExcerpt = (markdown: string, start: number, end: number) => {\n const excerpt = markdown.slice(start, end).trim();\n\n return excerpt.length > 0 ? excerpt : undefined;\n};\n\nconst toPatchMatch = (markdown: string, match: RawTextMatch, totalMatches: number): MarkdownPatchMatch => {\n const { lineStart, lineEnd } = getLineRange(markdown, match);\n const beforeStart = Math.max(0, match.start - EXCERPT_CONTEXT_CHARS);\n const afterEnd = Math.min(markdown.length, match.end + EXCERPT_CONTEXT_CHARS);\n const beforeText = markdown.slice(beforeStart, match.start);\n const afterText = markdown.slice(match.end, afterEnd);\n\n return {\n matchIndex: match.matchIndex,\n lineStart,\n lineEnd,\n text: match.text,\n beforeExcerpt: buildExcerpt(markdown, beforeStart, match.start),\n afterExcerpt: buildExcerpt(markdown, match.end, afterEnd),\n matchSha256: calculateMarkdownSha256(match.text),\n surroundingHash: calculateMarkdownSha256(JSON.stringify({ beforeText, targetText: match.text, afterText })),\n ...(match.matchIndex === 0 && totalMatches > 1 ? { positionHint: 'first' } : {}),\n ...(match.matchIndex === totalMatches - 1 && totalMatches > 1 ? { positionHint: 'last' } : {}),\n };\n};\n\nconst findExactTextMatches = (markdown: string, text: string) => {\n const matches: RawTextMatch[] = [];\n let searchStart = 0;\n\n while (searchStart <= markdown.length) {\n const start = markdown.indexOf(text, searchStart);\n\n if (start === -1) {\n break;\n }\n\n matches.push({\n matchIndex: matches.length,\n start,\n end: start + text.length,\n text,\n });\n searchStart = start + text.length;\n }\n\n return matches;\n};\n\nconst splitLines = (value: string) => {\n return value.split('\\n');\n};\n\nconst findSharedLineEdges = (beforeLines: string[], afterLines: string[]) => {\n let prefix = 0;\n const maxPrefix = Math.min(beforeLines.length, afterLines.length);\n\n while (prefix < maxPrefix && beforeLines[prefix] === afterLines[prefix]) {\n prefix += 1;\n }\n\n let suffix = 0;\n const maxSuffix = Math.min(beforeLines.length - prefix, afterLines.length - prefix);\n\n while (\n suffix < maxSuffix &&\n beforeLines[beforeLines.length - 1 - suffix] === afterLines[afterLines.length - 1 - suffix]\n ) {\n suffix += 1;\n }\n\n return {\n prefix,\n suffix,\n };\n};\n\nconst formatDiffRange = (lineIndex: number, lineCount: number) => {\n const lineNumber = lineIndex + 1;\n\n return lineCount === 1 ? String(lineNumber) : `${lineNumber},${lineCount}`;\n};\n\nexport const createUnifiedMarkdownDiff = (\n beforeMarkdown: string,\n afterMarkdown: string,\n contextLines: number | null = DIFF_CONTEXT_LINES,\n) => {\n const beforeLines = splitLines(beforeMarkdown);\n const afterLines = splitLines(afterMarkdown);\n const { prefix, suffix } = findSharedLineEdges(beforeLines, afterLines);\n const changedBeforeStart = prefix;\n const changedBeforeEnd = beforeLines.length - suffix;\n const changedAfterStart = prefix;\n const changedAfterEnd = afterLines.length - suffix;\n const displayBeforeStart = contextLines === null ? 0 : Math.max(0, changedBeforeStart - contextLines);\n const displayBeforeEnd =\n contextLines === null ? beforeLines.length : Math.min(beforeLines.length, changedBeforeEnd + contextLines);\n const displayAfterStart = contextLines === null ? 0 : Math.max(0, changedAfterStart - contextLines);\n const displayAfterEnd =\n contextLines === null ? afterLines.length : Math.min(afterLines.length, changedAfterEnd + contextLines);\n const diffLines = [\n '--- before.md',\n '+++ after.md',\n `@@ -${formatDiffRange(displayBeforeStart, displayBeforeEnd - displayBeforeStart)} +${formatDiffRange(displayAfterStart, displayAfterEnd - displayAfterStart)} @@`,\n ];\n\n for (let index = displayBeforeStart; index < changedBeforeStart; index += 1) {\n diffLines.push(` ${beforeLines[index]}`);\n }\n\n for (let index = changedBeforeStart; index < changedBeforeEnd; index += 1) {\n diffLines.push(`-${beforeLines[index]}`);\n }\n\n for (let index = changedAfterStart; index < changedAfterEnd; index += 1) {\n diffLines.push(`+${afterLines[index]}`);\n }\n\n for (let index = changedBeforeEnd; index < displayBeforeEnd; index += 1) {\n diffLines.push(` ${beforeLines[index]}`);\n }\n\n return diffLines.join('\\n');\n};\n\nconst countChangedLines = (beforeMarkdown: string, afterMarkdown: string) => {\n const beforeLines = splitLines(beforeMarkdown);\n const afterLines = splitLines(afterMarkdown);\n const { prefix, suffix } = findSharedLineEdges(beforeLines, afterLines);\n const removedLineCount = beforeLines.length - prefix - suffix;\n const addedLineCount = afterLines.length - prefix - suffix;\n\n return Math.max(removedLineCount, addedLineCount);\n};\n\nconst isMarkdownTokenWhitespace = (character: string) => /\\s/.test(character);\n\nexport const countExplicitTagTokens = (value: string) => {\n let count = 0;\n\n for (let index = 0; index < value.length; index += 1) {\n if (value[index] !== '[' || (value[index + 1] !== '@' && value[index + 1] !== '#')) {\n continue;\n }\n\n let cursor = index + 2;\n let isValid = cursor < value.length;\n\n while (cursor < value.length && value[cursor] !== ']') {\n if (value[cursor] === '[' || isMarkdownTokenWhitespace(value[cursor])) {\n isValid = false;\n break;\n }\n\n cursor += 1;\n }\n\n if (isValid && cursor < value.length && cursor > index + 2) {\n count += 1;\n index = cursor;\n continue;\n }\n\n if (!isValid) {\n index = Math.max(index, cursor - 1);\n }\n }\n\n return count;\n};\n\nexport const countMarkdownReferenceTokens = (value: string) => {\n let count = 0;\n let cursor = 0;\n\n while (cursor < value.length) {\n const start = value.indexOf('[[', cursor);\n\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf(']]', start + 2);\n\n if (end === -1) {\n break;\n }\n\n if (end > start + 2) {\n count += 1;\n }\n\n cursor = end + 2;\n }\n\n return count;\n};\n\nconst parseVersionTimestamp = (value: string) => {\n const timestamp = /^\\d+$/.test(value) ? Number(value) : Date.parse(value);\n\n return Number.isFinite(timestamp) ? timestamp : null;\n};\n\nconst noteVersionsMatch = (expectedUpdatedAt: string, currentUpdatedAt: string) => {\n const expectedTimestamp = parseVersionTimestamp(expectedUpdatedAt);\n const currentTimestamp = parseVersionTimestamp(currentUpdatedAt);\n\n return expectedTimestamp !== null && currentTimestamp !== null && expectedTimestamp === currentTimestamp;\n};\n\nconst getPreservationFailure = (\n beforeMarkdown: string,\n afterMarkdown: string,\n policy: MarkdownChangePolicy | undefined,\n): MarkdownChangeFailure | null => {\n const beforeTagCount = countExplicitTagTokens(beforeMarkdown);\n const afterTagCount = countExplicitTagTokens(afterMarkdown);\n\n if (policy?.preserveTags === true && afterTagCount < beforeTagCount) {\n return {\n status: 'failed',\n reason: 'TAG_TOKEN_DECREASED',\n message: 'The patch would reduce explicit tag tokens.',\n };\n }\n\n const beforeReferenceCount = countMarkdownReferenceTokens(beforeMarkdown);\n const afterReferenceCount = countMarkdownReferenceTokens(afterMarkdown);\n\n if (policy?.preserveReferences === true && afterReferenceCount < beforeReferenceCount) {\n return {\n status: 'failed',\n reason: 'REFERENCE_TOKEN_DECREASED',\n message: 'The patch would reduce note reference tokens.',\n };\n }\n\n return null;\n};\n\nconst collectWarnings = (\n beforeMarkdown: string,\n afterMarkdown: string,\n policy: MarkdownChangePolicy | undefined,\n): string[] => {\n const warnings: string[] = [];\n const beforeTagCount = countExplicitTagTokens(beforeMarkdown);\n const afterTagCount = countExplicitTagTokens(afterMarkdown);\n const shouldWarnTags = policy?.preserveTags === undefined || policy.preserveTags === 'warn';\n\n if (shouldWarnTags && afterTagCount < beforeTagCount) {\n warnings.push('TAG_TOKEN_COUNT_DECREASED');\n }\n\n const beforeReferenceCount = countMarkdownReferenceTokens(beforeMarkdown);\n const afterReferenceCount = countMarkdownReferenceTokens(afterMarkdown);\n const shouldWarnReferences = policy?.preserveReferences === undefined || policy.preserveReferences === 'warn';\n\n if (shouldWarnReferences && afterReferenceCount < beforeReferenceCount) {\n warnings.push('REFERENCE_TOKEN_COUNT_DECREASED');\n }\n\n return warnings;\n};\n\nconst validateBaseline = (\n note: MarkdownPatchNoteSnapshot,\n expectedUpdatedAt: string | undefined,\n baseMarkdownSha256: string | undefined,\n): MarkdownChangeFailure | null => {\n const beforeMarkdownSha256 = calculateMarkdownSha256(note.markdown);\n\n if (!expectedUpdatedAt && !baseMarkdownSha256) {\n return {\n status: 'failed',\n reason: 'MISSING_BASELINE',\n message: 'expectedUpdatedAt or baseMarkdownSha256 is required for markdown writes.',\n };\n }\n\n if (\n (expectedUpdatedAt && !noteVersionsMatch(expectedUpdatedAt, note.updatedAt)) ||\n (baseMarkdownSha256 && baseMarkdownSha256 !== beforeMarkdownSha256)\n ) {\n return {\n status: 'failed',\n reason: 'BASELINE_MISMATCH',\n message: 'The markdown write baseline does not match the current note.',\n };\n }\n\n return null;\n};\n\nconst validateChangeLimits = (\n beforeMarkdown: string,\n afterMarkdown: string,\n changedCharCount: number,\n policy: MarkdownChangePolicy | undefined,\n): MarkdownChangeFailure | null => {\n const changedLineCount = countChangedLines(beforeMarkdown, afterMarkdown);\n\n if (\n (policy?.maxChangedLines !== undefined && changedLineCount > policy.maxChangedLines) ||\n (policy?.maxChangedChars !== undefined && changedCharCount > policy.maxChangedChars)\n ) {\n return {\n status: 'failed',\n reason: 'CHANGE_LIMIT_EXCEEDED',\n message: 'The markdown write exceeds the configured change limit.',\n };\n }\n\n return null;\n};\n\nconst createChangePlan = ({\n note,\n afterMarkdown,\n changedCharCount,\n policy,\n diffContextLines = DIFF_CONTEXT_LINES,\n match,\n placement,\n}: {\n note: MarkdownPatchNoteSnapshot;\n afterMarkdown: string;\n changedCharCount: number;\n policy: MarkdownChangePolicy | undefined;\n diffContextLines?: number | null;\n match?: MarkdownChangeDryRun['match'];\n placement?: MarkdownAppendPlacement;\n}): MarkdownChangePlan | MarkdownChangeFailure => {\n if (!policy?.allowNoop && afterMarkdown === note.markdown) {\n return {\n status: 'failed',\n reason: 'NOOP',\n message: 'The markdown write would not change the note.',\n };\n }\n\n const preservationFailure = getPreservationFailure(note.markdown, afterMarkdown, policy);\n\n if (preservationFailure) {\n return preservationFailure;\n }\n\n const limitFailure = validateChangeLimits(note.markdown, afterMarkdown, changedCharCount, policy);\n\n if (limitFailure) {\n return limitFailure;\n }\n\n return {\n status: 'dry_run',\n note: {\n id: note.id,\n title: note.title,\n updatedAt: note.updatedAt,\n },\n ...(match ? { match } : {}),\n ...(placement ? { placement } : {}),\n proposed: {\n changedLineCount: countChangedLines(note.markdown, afterMarkdown),\n changedCharCount,\n beforeMarkdownSha256: calculateMarkdownSha256(note.markdown),\n afterMarkdownSha256: calculateMarkdownSha256(afterMarkdown),\n diff: createUnifiedMarkdownDiff(note.markdown, afterMarkdown, diffContextLines),\n },\n warnings: collectWarnings(note.markdown, afterMarkdown, policy),\n afterMarkdown,\n };\n};\n\nconst matchHasAnchors = (markdown: string, match: RawTextMatch, selector: ExactTextMarkdownPatchSelector) => {\n if (selector.before !== undefined && !markdown.slice(0, match.start).endsWith(selector.before)) {\n return false;\n }\n\n if (selector.after !== undefined && !markdown.slice(match.end).startsWith(selector.after)) {\n return false;\n }\n\n return true;\n};\n\nconst selectExactTextMatch = (\n markdown: string,\n selector: ExactTextMarkdownPatchSelector,\n):\n | { match: RawTextMatch; patchMatch: MarkdownPatchMatch }\n | MarkdownPatchNeedsDisambiguation\n | MarkdownChangeFailure => {\n if (selector.text.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_TARGET',\n message: 'Exact text selector must not be empty.',\n };\n }\n\n const rawMatches = findExactTextMatches(markdown, selector.text);\n\n if (rawMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'No exact text match was found in the current note.',\n };\n }\n\n const anchoredMatches = rawMatches.filter((match) => matchHasAnchors(markdown, match, selector));\n\n if (anchoredMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'ANCHOR_MISMATCH',\n message: 'Exact text matches were found, but before/after anchors did not match.',\n };\n }\n\n if (anchoredMatches.length > 1) {\n return {\n status: 'needs_disambiguation',\n reason: 'TARGET_AMBIGUOUS',\n matches: anchoredMatches.map((match) => toPatchMatch(markdown, match, rawMatches.length)),\n };\n }\n\n const match = anchoredMatches[0];\n\n return {\n match,\n patchMatch: toPatchMatch(markdown, match, rawMatches.length),\n };\n};\n\nconst selectMatchCandidate = (\n markdown: string,\n selector: MatchCandidateMarkdownPatchSelector,\n): { match: RawTextMatch; patchMatch: MarkdownPatchMatch } | MarkdownChangeFailure => {\n if (selector.text.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_TARGET',\n message: 'Match candidate selector text must not be empty.',\n };\n }\n\n const rawMatches = findExactTextMatches(markdown, selector.text);\n\n if (rawMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'TARGET_NOT_FOUND',\n message: 'No match candidate text was found in the current note.',\n };\n }\n\n const match = rawMatches.find((candidate) => candidate.matchIndex === selector.matchIndex);\n\n if (!match) {\n return {\n status: 'failed',\n reason: 'CANDIDATE_MISMATCH',\n message: 'The selected match index does not exist in the current note.',\n };\n }\n\n const patchMatch = toPatchMatch(markdown, match, rawMatches.length);\n const positionMatches = selector.positionHint === undefined || patchMatch.positionHint === selector.positionHint;\n\n if (\n patchMatch.lineStart !== selector.lineStart ||\n patchMatch.matchSha256 !== selector.matchSha256 ||\n patchMatch.surroundingHash !== selector.surroundingHash ||\n !positionMatches\n ) {\n return {\n status: 'failed',\n reason: 'CANDIDATE_MISMATCH',\n message: 'The selected match candidate no longer matches the current note context.',\n };\n }\n\n return {\n match,\n patchMatch,\n };\n};\n\nconst applyPatchOperation = (markdown: string, match: RawTextMatch, operation: MarkdownPatchOperation) => {\n if (operation.type === 'replace') {\n return {\n markdown: `${markdown.slice(0, match.start)}${operation.replacement}${markdown.slice(match.end)}`,\n changedCharCount: match.text.length + operation.replacement.length,\n };\n }\n\n if (operation.type === 'insert_before') {\n return {\n markdown: `${markdown.slice(0, match.start)}${operation.insertion}${markdown.slice(match.start)}`,\n changedCharCount: operation.insertion.length,\n };\n }\n\n return {\n markdown: `${markdown.slice(0, match.end)}${operation.insertion}${markdown.slice(match.end)}`,\n changedCharCount: operation.insertion.length,\n };\n};\n\nexport const buildMarkdownPatchPlan = (input: PreviewMarkdownPatchInput): MarkdownPatchPlanResult => {\n const baselineFailure = validateBaseline(input.note, input.expectedUpdatedAt, input.baseMarkdownSha256);\n\n if (baselineFailure) {\n return baselineFailure;\n }\n\n const selected =\n input.selector.type === 'exact_text'\n ? selectExactTextMatch(input.note.markdown, input.selector)\n : selectMatchCandidate(input.note.markdown, input.selector);\n\n if ('status' in selected) {\n return selected;\n }\n\n const patched = applyPatchOperation(input.note.markdown, selected.match, input.operation);\n const plan = createChangePlan({\n note: input.note,\n afterMarkdown: patched.markdown,\n changedCharCount: patched.changedCharCount,\n policy: input.policy,\n match: {\n count: 1,\n lineStart: selected.patchMatch.lineStart,\n lineEnd: selected.patchMatch.lineEnd,\n selectorType: input.selector.type,\n matchedTextSha256: selected.patchMatch.matchSha256,\n surroundingHash: selected.patchMatch.surroundingHash,\n },\n });\n\n return plan;\n};\n\nconst parseHeadingLine = (line: string) => {\n const match = /^(#{1,6})\\s+(.+?)\\s*#*\\s*$/.exec(line);\n\n if (!match) {\n return null;\n }\n\n return {\n level: match[1].length,\n heading: match[2].trim(),\n };\n};\n\nconst getLineStartOffsets = (lines: string[]) => {\n const offsets: number[] = [];\n let offset = 0;\n\n for (const line of lines) {\n offsets.push(offset);\n offset += line.length + 1;\n }\n\n return offsets;\n};\n\nconst findHeadingMatches = (markdown: string, placement: MarkdownAppendPlacementAfterHeading) => {\n const lines = splitLines(markdown);\n const offsets = getLineStartOffsets(lines);\n const headingLines = lines\n .map((line, index) => {\n const heading = parseHeadingLine(line);\n\n if (!heading) {\n return null;\n }\n\n return {\n ...heading,\n lineIndex: index,\n start: offsets[index],\n };\n })\n .filter((heading): heading is Omit<HeadingMatch, 'nextSectionStart'> => heading !== null);\n const matches = headingLines.filter((heading) => {\n return (\n heading.heading === placement.heading &&\n (placement.level === undefined || heading.level === placement.level)\n );\n });\n\n return matches.map((match) => {\n const nextHeading = headingLines.find(\n (heading) => heading.lineIndex > match.lineIndex && heading.level <= match.level,\n );\n\n return {\n ...match,\n nextSectionStart: nextHeading?.start ?? markdown.length,\n };\n });\n};\n\nconst appendWithSeparator = (prefix: string, insertion: string, separator: '\\n\\n' | '\\n') => {\n if (prefix.length === 0) {\n return insertion;\n }\n\n return `${prefix}${prefix.endsWith(separator) ? '' : separator}${insertion}`;\n};\n\nconst applyAppendPlacement = (\n markdown: string,\n insertion: string,\n placement: MarkdownAppendPlacement,\n separator: '\\n\\n' | '\\n',\n): { markdown: string; placement: MarkdownAppendPlacement } | MarkdownChangeFailure => {\n if (insertion.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_INSERTION',\n message: 'Append insertion must not be empty.',\n };\n }\n\n if (placement.type === 'end') {\n return {\n markdown: appendWithSeparator(markdown, insertion, separator),\n placement,\n };\n }\n\n if (\n placement.level !== undefined &&\n (!Number.isInteger(placement.level) || placement.level < 1 || placement.level > 6)\n ) {\n return {\n status: 'failed',\n reason: 'INVALID_HEADING_LEVEL',\n message: 'Heading level must be an integer from 1 to 6.',\n };\n }\n\n const headingMatches = findHeadingMatches(markdown, placement);\n\n if (headingMatches.length === 0) {\n return {\n status: 'failed',\n reason: 'HEADING_NOT_FOUND',\n message: 'The requested heading was not found.',\n };\n }\n\n if (headingMatches.length > 1) {\n return {\n status: 'failed',\n reason: 'HEADING_AMBIGUOUS',\n message: 'The requested heading appears more than once.',\n };\n }\n\n const [headingMatch] = headingMatches;\n const prefix = markdown.slice(0, headingMatch.nextSectionStart);\n const suffix = markdown.slice(headingMatch.nextSectionStart);\n const prefixWithInsertion = appendWithSeparator(prefix, insertion, separator);\n const nextMarkdown =\n suffix.length === 0\n ? prefixWithInsertion\n : `${prefixWithInsertion}${prefixWithInsertion.endsWith(separator) ? '' : separator}${suffix}`;\n\n return {\n markdown: nextMarkdown,\n placement,\n };\n};\n\nexport const buildMarkdownAppendPlan = (input: PreviewMarkdownAppendInput): MarkdownAppendPlanResult => {\n const baselineFailure = validateBaseline(input.note, input.expectedUpdatedAt, input.baseMarkdownSha256);\n\n if (baselineFailure) {\n return baselineFailure;\n }\n\n const placement = input.placement ?? { type: 'end' as const };\n const separator = input.separator ?? '\\n\\n';\n const appended = applyAppendPlacement(input.note.markdown, input.insertion, placement, separator);\n\n if ('status' in appended) {\n return appended;\n }\n\n return createChangePlan({\n note: input.note,\n afterMarkdown: appended.markdown,\n changedCharCount: input.insertion.length,\n policy: input.policy,\n placement: appended.placement,\n });\n};\n\nexport const buildMarkdownReplacePlan = (input: PreviewMarkdownReplaceInput): MarkdownReplacePlanResult => {\n const baselineFailure = validateBaseline(input.note, input.expectedUpdatedAt, input.baseMarkdownSha256);\n\n if (baselineFailure) {\n return baselineFailure;\n }\n\n if (input.replacement.length === 0) {\n return {\n status: 'failed',\n reason: 'EMPTY_REPLACEMENT',\n message: 'Replacement markdown must not be empty.',\n };\n }\n\n return createChangePlan({\n note: input.note,\n afterMarkdown: input.replacement,\n changedCharCount: input.note.markdown.length + input.replacement.length,\n policy: input.policy,\n diffContextLines: null,\n });\n};\n\nconst toPreviewResult = (plan: MarkdownChangePlan): MarkdownChangeDryRun => {\n return {\n status: 'dry_run',\n note: plan.note,\n ...(plan.match ? { match: plan.match } : {}),\n ...(plan.placement ? { placement: plan.placement } : {}),\n proposed: plan.proposed,\n warnings: plan.warnings,\n };\n};\n\nexport const previewMarkdownPatch = (input: PreviewMarkdownPatchInput): MarkdownPatchPreviewResult => {\n const plan = buildMarkdownPatchPlan(input);\n\n if (plan.status !== 'dry_run') {\n return plan;\n }\n\n return toPreviewResult(plan);\n};\n\nexport const previewMarkdownAppend = (\n input: PreviewMarkdownAppendInput,\n): MarkdownChangeDryRun | MarkdownChangeFailure => {\n const plan = buildMarkdownAppendPlan(input);\n\n if (plan.status !== 'dry_run') {\n return plan;\n }\n\n return toPreviewResult(plan);\n};\n\nexport const previewMarkdownReplace = (\n input: PreviewMarkdownReplaceInput,\n): MarkdownChangeDryRun | MarkdownChangeFailure => {\n const plan = buildMarkdownReplacePlan(input);\n\n if (plan.status !== 'dry_run') {\n return plan;\n }\n\n return toPreviewResult(plan);\n};\n"],"mappings":"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","names":["match"]}
@@ -168,6 +168,255 @@ function preprocessMarkdownExplicitTags(markdown) {
168
168
  placeholderToTag
169
169
  };
170
170
  }
171
+ const MARKDOWN_ANGLE_BRACKET_TOKEN_PATTERN = /<([^<>\n]+)>/g;
172
+ const MARKDOWN_NUMERIC_TILDE_RANGE_PATTERN = /(\d)~(?=\d)/g;
173
+ const MARKDOWN_FENCED_CODE_PATTERN = /^ {0,3}(`{3,}|~{3,})/;
174
+ const ANGLE_BRACKET_PLACEHOLDER_PREFIX = "\uE000OBANGLE";
175
+ const ANGLE_BRACKET_PLACEHOLDER_SUFFIX = "\uE001";
176
+ const NUMERIC_TILDE_RANGE_PLACEHOLDER_PREFIX = "\uE000OBTILDE";
177
+ const NUMERIC_TILDE_RANGE_PLACEHOLDER_SUFFIX = "\uE001";
178
+ function isMarkdownAutolinkAngleBracketText(innerText) {
179
+ if (innerText !== innerText.trim()) {
180
+ return false;
181
+ }
182
+ return /^[a-z][a-z0-9.+-]{1,31}:[^\s<>]*$/i.test(innerText) || /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(innerText);
183
+ }
184
+ function countLiteralAngleBracketTextTokens(markdown) {
185
+ const tokenCounts = /* @__PURE__ */ new Map();
186
+ for (const match of markdown.matchAll(MARKDOWN_ANGLE_BRACKET_TOKEN_PATTERN)) {
187
+ const token = match[0];
188
+ const innerText = match[1] ?? "";
189
+ if (!token || isMarkdownAutolinkAngleBracketText(innerText)) {
190
+ continue;
191
+ }
192
+ tokenCounts.set(token, (tokenCounts.get(token) ?? 0) + 1);
193
+ }
194
+ return tokenCounts;
195
+ }
196
+ function extractLiteralAngleBracketTextTokens(markdown) {
197
+ return [...countLiteralAngleBracketTextTokens(markdown).keys()];
198
+ }
199
+ function hasLiteralAngleBracketTextTokenLoss(sourceMarkdown, renderedMarkdown) {
200
+ const sourceCounts = countLiteralAngleBracketTextTokens(sourceMarkdown);
201
+ if (sourceCounts.size === 0) {
202
+ return false;
203
+ }
204
+ const renderedCounts = countLiteralAngleBracketTextTokens(renderedMarkdown);
205
+ for (const [token, sourceCount] of sourceCounts) {
206
+ if ((renderedCounts.get(token) ?? 0) < sourceCount) {
207
+ return true;
208
+ }
209
+ }
210
+ return false;
211
+ }
212
+ function countNumericTildeRangeMarkers(markdown) {
213
+ return [...markdown.matchAll(MARKDOWN_NUMERIC_TILDE_RANGE_PATTERN)].length;
214
+ }
215
+ function hasNumericTildeRangeMarkers(markdown) {
216
+ return countNumericTildeRangeMarkers(markdown) > 0;
217
+ }
218
+ function hasNumericTildeRangeMarkerLoss(sourceMarkdown, renderedMarkdown) {
219
+ const sourceCount = countNumericTildeRangeMarkers(sourceMarkdown);
220
+ return sourceCount > 0 && countNumericTildeRangeMarkers(renderedMarkdown) < sourceCount;
221
+ }
222
+ function protectMarkdownNumericTildeRanges(markdown) {
223
+ const protectedLines = [];
224
+ const placeholderToToken = /* @__PURE__ */ new Map();
225
+ let activeFence = null;
226
+ for (const line of markdown.split(/(?<=\n)/)) {
227
+ const { body: lineBody, lineEnding } = splitMarkdownLineEnding(line);
228
+ const fenceMatch = lineBody.match(MARKDOWN_FENCED_CODE_PATTERN);
229
+ if (activeFence) {
230
+ protectedLines.push(line);
231
+ if (isClosingFenceLine(lineBody, activeFence)) {
232
+ activeFence = null;
233
+ }
234
+ continue;
235
+ }
236
+ if (fenceMatch?.[1]) {
237
+ const marker = fenceMatch[1][0];
238
+ activeFence = {
239
+ marker,
240
+ length: fenceMatch[1].length
241
+ };
242
+ protectedLines.push(line);
243
+ continue;
244
+ }
245
+ if (/^(?: {4,}|\t)/.test(lineBody)) {
246
+ protectedLines.push(line);
247
+ continue;
248
+ }
249
+ protectedLines.push(`${protectMarkdownLineNumericTildeRanges(lineBody, placeholderToToken)}${lineEnding}`);
250
+ }
251
+ return {
252
+ markdown: protectedLines.join(""),
253
+ placeholderToToken
254
+ };
255
+ }
256
+ function protectMarkdownTextAngleBrackets(markdown) {
257
+ const protectedLines = [];
258
+ const placeholderToToken = /* @__PURE__ */ new Map();
259
+ let activeFence = null;
260
+ for (const line of markdown.split(/(?<=\n)/)) {
261
+ const { body: lineBody, lineEnding } = splitMarkdownLineEnding(line);
262
+ const fenceMatch = lineBody.match(MARKDOWN_FENCED_CODE_PATTERN);
263
+ if (activeFence) {
264
+ protectedLines.push(line);
265
+ if (isClosingFenceLine(lineBody, activeFence)) {
266
+ activeFence = null;
267
+ }
268
+ continue;
269
+ }
270
+ if (fenceMatch?.[1]) {
271
+ const marker = fenceMatch[1][0];
272
+ activeFence = {
273
+ marker,
274
+ length: fenceMatch[1].length
275
+ };
276
+ protectedLines.push(line);
277
+ continue;
278
+ }
279
+ if (/^(?: {4,}|\t)/.test(lineBody)) {
280
+ protectedLines.push(line);
281
+ continue;
282
+ }
283
+ protectedLines.push(`${protectMarkdownLineTextAngleBrackets(lineBody, placeholderToToken)}${lineEnding}`);
284
+ }
285
+ return {
286
+ markdown: protectedLines.join(""),
287
+ placeholderToToken
288
+ };
289
+ }
290
+ function splitMarkdownLineEnding(line) {
291
+ if (line.endsWith("\r\n")) {
292
+ return {
293
+ body: line.slice(0, -2),
294
+ lineEnding: "\r\n"
295
+ };
296
+ }
297
+ if (line.endsWith("\n")) {
298
+ return {
299
+ body: line.slice(0, -1),
300
+ lineEnding: "\n"
301
+ };
302
+ }
303
+ return {
304
+ body: line,
305
+ lineEnding: ""
306
+ };
307
+ }
308
+ function isClosingFenceLine(line, fence) {
309
+ const escapedMarker = fence.marker === "`" ? "`" : "~";
310
+ return new RegExp(`^ {0,3}${escapedMarker}{${fence.length},} *$`).test(line);
311
+ }
312
+ function protectMarkdownLineTextAngleBrackets(line, placeholderToToken) {
313
+ let result = "";
314
+ let cursor = 0;
315
+ while (cursor < line.length) {
316
+ const codeStart = line.indexOf("`", cursor);
317
+ if (codeStart === -1) {
318
+ result += replaceLiteralAngleBracketTextTokens(line.slice(cursor), placeholderToToken);
319
+ break;
320
+ }
321
+ result += replaceLiteralAngleBracketTextTokens(line.slice(cursor, codeStart), placeholderToToken);
322
+ const delimiterLength = countRepeatedCharacter(line, codeStart, "`");
323
+ const codeEnd = line.indexOf("`".repeat(delimiterLength), codeStart + delimiterLength);
324
+ if (codeEnd === -1) {
325
+ result += replaceLiteralAngleBracketTextTokens(line.slice(codeStart), placeholderToToken);
326
+ break;
327
+ }
328
+ const codeEndExclusive = codeEnd + delimiterLength;
329
+ result += line.slice(codeStart, codeEndExclusive);
330
+ cursor = codeEndExclusive;
331
+ }
332
+ return result;
333
+ }
334
+ function protectMarkdownLineNumericTildeRanges(line, placeholderToToken) {
335
+ let result = "";
336
+ let cursor = 0;
337
+ while (cursor < line.length) {
338
+ const protectedSpan = findNextMarkdownProtectedSpan(line, cursor);
339
+ if (!protectedSpan) {
340
+ result += replaceNumericTildeRangeMarkers(line.slice(cursor), placeholderToToken);
341
+ break;
342
+ }
343
+ result += replaceNumericTildeRangeMarkers(line.slice(cursor, protectedSpan.start), placeholderToToken);
344
+ result += line.slice(protectedSpan.start, protectedSpan.end);
345
+ cursor = protectedSpan.end;
346
+ }
347
+ return result;
348
+ }
349
+ function findNextMarkdownProtectedSpan(line, cursor) {
350
+ const codeSpan = findNextInlineCodeSpan(line, cursor);
351
+ const linkDestinationSpan = findNextMarkdownLinkDestinationSpan(line, cursor);
352
+ if (!codeSpan) {
353
+ return linkDestinationSpan;
354
+ }
355
+ if (!linkDestinationSpan) {
356
+ return codeSpan;
357
+ }
358
+ return codeSpan.start <= linkDestinationSpan.start ? codeSpan : linkDestinationSpan;
359
+ }
360
+ function findNextInlineCodeSpan(line, cursor) {
361
+ const codeStart = line.indexOf("`", cursor);
362
+ if (codeStart === -1) {
363
+ return null;
364
+ }
365
+ const delimiterLength = countRepeatedCharacter(line, codeStart, "`");
366
+ const codeEnd = line.indexOf("`".repeat(delimiterLength), codeStart + delimiterLength);
367
+ if (codeEnd === -1) {
368
+ return null;
369
+ }
370
+ return {
371
+ start: codeStart,
372
+ end: codeEnd + delimiterLength
373
+ };
374
+ }
375
+ function findNextMarkdownLinkDestinationSpan(line, cursor) {
376
+ const linkDestinationPrefix = line.indexOf("](", cursor);
377
+ if (linkDestinationPrefix === -1) {
378
+ return null;
379
+ }
380
+ const destinationStart = linkDestinationPrefix + 2;
381
+ const destinationEnd = line.indexOf(")", destinationStart);
382
+ if (destinationEnd === -1) {
383
+ return null;
384
+ }
385
+ return {
386
+ start: destinationStart,
387
+ end: destinationEnd
388
+ };
389
+ }
390
+ function replaceLiteralAngleBracketTextTokens(text, placeholderToToken) {
391
+ return text.replace(MARKDOWN_ANGLE_BRACKET_TOKEN_PATTERN, (match, innerText) => {
392
+ if (isMarkdownAutolinkAngleBracketText(innerText)) {
393
+ return match;
394
+ }
395
+ const placeholder = createAngleBracketPlaceholder(placeholderToToken.size);
396
+ placeholderToToken.set(placeholder, match);
397
+ return placeholder;
398
+ });
399
+ }
400
+ function replaceNumericTildeRangeMarkers(text, placeholderToToken) {
401
+ return text.replace(MARKDOWN_NUMERIC_TILDE_RANGE_PATTERN, (match, leadingDigit) => {
402
+ const placeholder = createNumericTildeRangePlaceholder(placeholderToToken.size);
403
+ placeholderToToken.set(placeholder, "~");
404
+ return `${leadingDigit}${placeholder}`;
405
+ });
406
+ }
407
+ function createAngleBracketPlaceholder(index) {
408
+ return `${ANGLE_BRACKET_PLACEHOLDER_PREFIX}${index}${ANGLE_BRACKET_PLACEHOLDER_SUFFIX}`;
409
+ }
410
+ function createNumericTildeRangePlaceholder(index) {
411
+ return `${NUMERIC_TILDE_RANGE_PLACEHOLDER_PREFIX}${index}${NUMERIC_TILDE_RANGE_PLACEHOLDER_SUFFIX}`;
412
+ }
413
+ function countRepeatedCharacter(value, start, character) {
414
+ let cursor = start;
415
+ while (value[cursor] === character) {
416
+ cursor += 1;
417
+ }
418
+ return cursor - start;
419
+ }
171
420
  function findTagPlaceholderAtCursor(text, cursor, placeholderToTag) {
172
421
  for (const [placeholder, tagToken] of placeholderToTag.entries()) {
173
422
  if (text.startsWith(placeholder, cursor)) {
@@ -197,6 +446,39 @@ function restoreRemainingTagPlaceholders(blocks, placeholderToTag) {
197
446
  })
198
447
  );
199
448
  }
449
+ function restoreProtectedTextPlaceholders(blocks, placeholderToToken) {
450
+ if (placeholderToToken.size === 0) {
451
+ return blocks;
452
+ }
453
+ return mapBlocks(
454
+ blocks,
455
+ (content) => mapBlockContent(
456
+ content,
457
+ (inline) => restoreProtectedTextInValue(inline, placeholderToToken)
458
+ )
459
+ );
460
+ }
461
+ function restoreProtectedTextInValue(value, placeholderToToken) {
462
+ if (typeof value === "string") {
463
+ return restoreProtectedText(value, placeholderToToken);
464
+ }
465
+ if (Array.isArray(value)) {
466
+ return value.map((item) => restoreProtectedTextInValue(item, placeholderToToken));
467
+ }
468
+ if (value && typeof value === "object") {
469
+ return Object.fromEntries(
470
+ Object.entries(value).map(([key, item]) => [key, restoreProtectedTextInValue(item, placeholderToToken)])
471
+ );
472
+ }
473
+ return value;
474
+ }
475
+ function restoreProtectedText(text, placeholderToToken) {
476
+ let restoredText = text;
477
+ for (const [placeholder, token] of placeholderToToken.entries()) {
478
+ restoredText = restoredText.split(placeholder).join(token);
479
+ }
480
+ return restoredText;
481
+ }
200
482
  function createTextInline(text, styles = {}) {
201
483
  return {
202
484
  type: "text",
@@ -331,13 +613,42 @@ async function blocksToMarkdown(contentJson) {
331
613
  async function markdownToBlocksJson(markdown, deps = defaultMarkdownImportDeps) {
332
614
  const editor = getEditor();
333
615
  const preprocessedMarkdown = preprocessMarkdownExplicitTags(markdown);
334
- const blocks = await editor.tryParseMarkdownToBlocks(preprocessedMarkdown.markdown);
335
- const restoredBlocks = await restoreCustomInlineContent(
336
- blocks,
616
+ const tildeProtectedMarkdown = protectMarkdownNumericTildeRanges(preprocessedMarkdown.markdown);
617
+ const contentJson = await parseMarkdownToContentJson(
618
+ editor,
619
+ tildeProtectedMarkdown.markdown,
337
620
  deps,
338
- preprocessedMarkdown.placeholderToTag
621
+ preprocessedMarkdown.placeholderToTag,
622
+ tildeProtectedMarkdown.placeholderToToken
623
+ );
624
+ if (extractLiteralAngleBracketTextTokens(preprocessedMarkdown.markdown).length === 0) {
625
+ return contentJson;
626
+ }
627
+ if (!hasLiteralAngleBracketTextTokenLoss(preprocessedMarkdown.markdown, await blocksToMarkdown(contentJson))) {
628
+ return contentJson;
629
+ }
630
+ const protectedMarkdown = protectMarkdownTextAngleBrackets(tildeProtectedMarkdown.markdown);
631
+ const placeholderToToken = new Map([
632
+ ...tildeProtectedMarkdown.placeholderToToken,
633
+ ...protectedMarkdown.placeholderToToken
634
+ ]);
635
+ return parseMarkdownToContentJson(
636
+ editor,
637
+ protectedMarkdown.markdown,
638
+ deps,
639
+ preprocessedMarkdown.placeholderToTag,
640
+ placeholderToToken
641
+ );
642
+ }
643
+ async function parseMarkdownToContentJson(editor, markdown, deps, placeholderToTag, placeholderToProtectedTextToken = /* @__PURE__ */ new Map()) {
644
+ const blocks = await editor.tryParseMarkdownToBlocks(markdown);
645
+ const restoredBlocks = await restoreCustomInlineContent(blocks, deps, placeholderToTag);
646
+ const restoredTagBlocks = restoreRemainingTagPlaceholders(restoredBlocks, placeholderToTag);
647
+ const restoredProtectedTextBlocks = restoreProtectedTextPlaceholders(
648
+ restoredTagBlocks,
649
+ placeholderToProtectedTextToken
339
650
  );
340
- return JSON.stringify(restoreRemainingTagPlaceholders(restoredBlocks, preprocessedMarkdown.placeholderToTag));
651
+ return JSON.stringify(restoredProtectedTextBlocks);
341
652
  }
342
653
  function extractTagIdsFromContentJson(contentJson) {
343
654
  const blocks = parseBlockNoteContent(contentJson);
@@ -374,7 +685,11 @@ function countReferenceInlinesFromContentJson(contentJson) {
374
685
  export {
375
686
  blocksToMarkdown,
376
687
  countReferenceInlinesFromContentJson,
688
+ extractLiteralAngleBracketTextTokens,
377
689
  extractTagIdsFromContentJson,
690
+ hasLiteralAngleBracketTextTokenLoss,
691
+ hasNumericTildeRangeMarkerLoss,
692
+ hasNumericTildeRangeMarkers,
378
693
  hasUnsupportedMarkdownBlocks,
379
694
  markdownToBlocksJson
380
695
  };