xml-diff-kit 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts","../src/normalize.ts","../src/parse.ts","../src/text-diff.ts","../src/diff.ts","../src/serialize.ts","../src/format.ts","../src/patch.ts"],"sourcesContent":["import type { XmlElementNode, XmlNode } from './types.js';\r\n\r\n/** Return true when a normalized XML node is an element node. */\r\nexport function isElementNode(node: XmlNode): node is XmlElementNode {\r\n return node.type === 'element';\r\n}\r\n\r\n/**\r\n * Deep-clone a normalized XML node.\r\n *\r\n * `structuredClone` is available in the supported Node.js versions and modern\r\n * browsers. The AST is plain data, so structured cloning is sufficient and keeps\r\n * the library free of an additional cloning dependency.\r\n */\r\nexport function cloneXmlNode<T extends XmlNode>(node: T): T {\r\n return structuredClone(node) as T;\r\n}\r\n\r\n/** Return a new record sorted by key for deterministic serialization/diffing. */\r\nexport function sortRecord(record: Record<string, string>): Record<string, string> {\r\n return Object.fromEntries(\r\n Object.entries(record).sort(([left], [right]) => left.localeCompare(right)),\r\n );\r\n}\r\n\r\n/** Escape XML text-node content. */\r\nexport function escapeXmlText(value: string): string {\r\n return value\r\n .replaceAll('&', '&amp;')\r\n .replaceAll('<', '&lt;')\r\n .replaceAll('>', '&gt;');\r\n}\r\n\r\n/** Escape XML attribute values. */\r\nexport function escapeXmlAttr(value: string): string {\r\n return escapeXmlText(value).replaceAll('\"', '&quot;');\r\n}\r\n\r\n/**\r\n * Build a stable semantic key for an element using the first matching key attr.\r\n *\r\n * The key includes the element name to avoid treating `<step id=\"1\"/>` and\r\n * `<figure id=\"1\"/>` as the same logical node.\r\n */\r\nexport function getNodeKey(node: XmlNode, keyAttrs: string[] = []): string | undefined {\r\n if (!isElementNode(node)) return undefined;\r\n\r\n for (const keyAttr of keyAttrs) {\r\n const value = node.attrs[keyAttr];\r\n if (value !== undefined) {\r\n return `${node.name}:${keyAttr}=${value}`;\r\n }\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Format one absolute-path segment for a node.\r\n *\r\n * Every segment includes a numeric sibling index, which is the executable part\r\n * used by patching. When a key attribute is available, the segment also includes\r\n * a readable key hint such as `step[@id=\"s1\"][0]`.\r\n */\r\nexport function formatPathSegment(node: XmlNode, index: number, keyAttrs: string[] = []): string {\r\n if (node.type === 'text') return `text()[${index}]`;\r\n if (node.type === 'comment') return `comment()[${index}]`;\r\n\r\n const keyAttr = keyAttrs.find((attr) => node.attrs[attr] !== undefined);\r\n const keyValue = keyAttr ? node.attrs[keyAttr] : undefined;\r\n const keyPart = keyAttr && keyValue !== undefined ? `[@${keyAttr}=\"${keyValue}\"]` : '';\r\n\r\n return `${node.name}${keyPart}[${index}]`;\r\n}\r\n","import type { XmlDiffOptions, XmlNode } from './types.js';\r\nimport { cloneXmlNode, sortRecord } from './utils.js';\r\n\r\n/**\r\n * Normalize an XML AST before diffing or patching.\r\n *\r\n * Normalization is where callers define which XML differences are meaningful.\r\n * For example, formatted indentation can be ignored with `ignoreWhitespaceText`,\r\n * comments can be ignored with `ignoreComments`, and attribute output can be\r\n * made deterministic with `sortAttributes`.\r\n *\r\n * The input node is cloned first. Callers can safely reuse their original AST\r\n * after normalization without worrying about mutation.\r\n */\r\nexport function normalizeXml(node: XmlNode, options: XmlDiffOptions = {}): XmlNode {\r\n const cloned = cloneXmlNode(node);\r\n const normalized = normalizeNode(cloned, options);\r\n\r\n if (!normalized) {\r\n throw new Error('Cannot normalize an empty XML document.');\r\n }\r\n\r\n return normalized;\r\n}\r\n\r\n/**\r\n * Normalize one node recursively.\r\n *\r\n * The function returns `null` for nodes that should be removed from the logical\r\n * comparison, such as whitespace-only text nodes or ignored comments.\r\n */\r\nfunction normalizeNode(node: XmlNode, options: XmlDiffOptions): XmlNode | null {\r\n if (node.type === 'text') {\r\n const text = options.trimText ? node.text.trim() : node.text;\r\n\r\n if (options.ignoreWhitespaceText && text.trim() === '') {\r\n return null;\r\n }\r\n\r\n return {\r\n type: 'text',\r\n text,\r\n };\r\n }\r\n\r\n if (node.type === 'comment') {\r\n if (options.ignoreComments) return null;\r\n\r\n return node;\r\n }\r\n\r\n const children = node.children\r\n .map((child) => normalizeNode(child, options))\r\n .filter((child): child is XmlNode => Boolean(child));\r\n\r\n return {\r\n ...node,\r\n attrs: options.sortAttributes ? sortRecord(node.attrs) : { ...node.attrs },\r\n children,\r\n };\r\n}\r\n","import { DOMParser } from '@xmldom/xmldom';\r\n\r\nimport type { XmlNode } from './types.js';\r\n\r\n/**\r\n * Parse an XML string into the library's normalized XML AST.\r\n *\r\n * This function is intentionally stricter than the default `@xmldom/xmldom`\r\n * behavior: parser warnings are treated as invalid XML. This is important for\r\n * a diff/patch library because silently recovering malformed XML can produce\r\n * surprising paths and operations.\r\n *\r\n * Only element, text, and comment nodes are currently preserved. Processing\r\n * instructions, doctypes, and other DOM node types are ignored during child\r\n * traversal until the public AST grows explicit representations for them.\r\n */\r\nexport function parseXml(xml: string): XmlNode {\r\n const doc = new DOMParser({\r\n errorHandler: {\r\n warning: (message) => {\r\n throw new Error(`Invalid XML: ${message}`);\r\n },\r\n error: (message) => {\r\n throw new Error(`Invalid XML: ${message}`);\r\n },\r\n fatalError: (message) => {\r\n throw new Error(`Invalid XML: ${message}`);\r\n },\r\n },\r\n }).parseFromString(xml, 'application/xml');\r\n\r\n if (!doc.documentElement) {\r\n throw new Error('Invalid XML: missing document element.');\r\n }\r\n\r\n return fromDomNode(doc.documentElement);\r\n}\r\n\r\n/** Convert a DOM node into the serializable `XmlNode` AST shape. */\r\nfunction fromDomNode(node: Node): XmlNode {\r\n if (node.nodeType === 1) {\r\n const element = node as Element;\r\n const attrs: Record<string, string> = {};\r\n\r\n // Preserve attribute names and values exactly as reported by the parser.\r\n // Attribute ordering can be made deterministic later by `normalizeXml`.\r\n for (let index = 0; index < element.attributes.length; index += 1) {\r\n const attr = element.attributes.item(index);\r\n if (attr) attrs[attr.name] = attr.value;\r\n }\r\n\r\n const children: XmlNode[] = [];\r\n\r\n // Preserve only node kinds currently represented by the public AST.\r\n for (let index = 0; index < element.childNodes.length; index += 1) {\r\n const child = element.childNodes.item(index);\r\n\r\n if (child.nodeType === 1 || child.nodeType === 3 || child.nodeType === 8) {\r\n children.push(fromDomNode(child));\r\n }\r\n }\r\n\r\n return {\r\n type: 'element',\r\n name: element.nodeName,\r\n namespaceURI: element.namespaceURI ?? null,\r\n attrs,\r\n children,\r\n };\r\n }\r\n\r\n if (node.nodeType === 3) {\r\n return {\r\n type: 'text',\r\n text: node.nodeValue ?? '',\r\n };\r\n }\r\n\r\n if (node.nodeType === 8) {\r\n return {\r\n type: 'comment',\r\n text: node.nodeValue ?? '',\r\n };\r\n }\r\n\r\n throw new Error(`Unsupported XML node type: ${node.nodeType}`);\r\n}\r\n","import type { TextChange, TextDiffSegment } from './types.js';\r\n\r\n/**\r\n * Diff two text values and return both patch-oriented and display-oriented data.\r\n *\r\n * `changes` is suitable for patch/review workflows because each item includes\r\n * an offset in the old text. `segments` is suitable for UI rendering because it\r\n * preserves a readable sequence of equal/insert/delete chunks.\r\n *\r\n * The implementation works on Unicode code points via `Array.from`, so offsets\r\n * are more predictable for emoji and other non-BMP characters than raw\r\n * JavaScript UTF-16 indexes.\r\n */\r\nexport function diffText(\r\n oldValue: string,\r\n newValue: string,\r\n): {\r\n changes: TextChange[];\r\n segments: TextDiffSegment[];\r\n} {\r\n if (oldValue === newValue) {\r\n return {\r\n changes: [],\r\n segments: [{ type: 'equal', text: oldValue }],\r\n };\r\n }\r\n\r\n const oldChars = Array.from(oldValue);\r\n const newChars = Array.from(newValue);\r\n const segments = buildDiffSegments(oldChars, newChars);\r\n\r\n return {\r\n changes: segmentsToChanges(segments),\r\n segments,\r\n };\r\n}\r\n\r\n/**\r\n * Build display segments using a classic LCS dynamic-programming table.\r\n *\r\n * This is intentionally simple and deterministic for the first version. It is\r\n * not the most memory-efficient diff algorithm for very large text nodes, but\r\n * it produces stable, easy-to-understand segments for typical XML text content\r\n * such as paragraphs, titles, and short inline text nodes.\r\n */\r\nfunction buildDiffSegments(oldChars: string[], newChars: string[]): TextDiffSegment[] {\r\n const rows = oldChars.length + 1;\r\n const cols = newChars.length + 1;\r\n const dp: number[][] = Array.from({ length: rows }, () => Array.from({ length: cols }, () => 0));\r\n\r\n // Fill the LCS length table from bottom-right to top-left.\r\n for (let oldIndex = oldChars.length - 1; oldIndex >= 0; oldIndex -= 1) {\r\n for (let newIndex = newChars.length - 1; newIndex >= 0; newIndex -= 1) {\r\n if (oldChars[oldIndex] === newChars[newIndex]) {\r\n dp[oldIndex]![newIndex] = dp[oldIndex + 1]![newIndex + 1]! + 1;\r\n } else {\r\n dp[oldIndex]![newIndex] = Math.max(dp[oldIndex + 1]![newIndex]!, dp[oldIndex]![newIndex + 1]!);\r\n }\r\n }\r\n }\r\n\r\n const segments: TextDiffSegment[] = [];\r\n let oldIndex = 0;\r\n let newIndex = 0;\r\n\r\n // Walk the table to produce an edit script. When both options are equal,\r\n // deletion is preferred first so a delete+insert pair can later become a\r\n // replaceTextRange operation.\r\n while (oldIndex < oldChars.length && newIndex < newChars.length) {\r\n if (oldChars[oldIndex] === newChars[newIndex]) {\r\n pushSegment(segments, { type: 'equal', text: oldChars[oldIndex]! });\r\n oldIndex += 1;\r\n newIndex += 1;\r\n } else if (dp[oldIndex + 1]![newIndex]! >= dp[oldIndex]![newIndex + 1]!) {\r\n pushSegment(segments, { type: 'delete', text: oldChars[oldIndex]! });\r\n oldIndex += 1;\r\n } else {\r\n pushSegment(segments, { type: 'insert', text: newChars[newIndex]! });\r\n newIndex += 1;\r\n }\r\n }\r\n\r\n while (oldIndex < oldChars.length) {\r\n pushSegment(segments, { type: 'delete', text: oldChars[oldIndex]! });\r\n oldIndex += 1;\r\n }\r\n\r\n while (newIndex < newChars.length) {\r\n pushSegment(segments, { type: 'insert', text: newChars[newIndex]! });\r\n newIndex += 1;\r\n }\r\n\r\n return segments;\r\n}\r\n\r\n/** Convert display segments into offset-based patch changes. */\r\nfunction segmentsToChanges(segments: TextDiffSegment[]): TextChange[] {\r\n const changes: TextChange[] = [];\r\n let offset = 0;\r\n let index = 0;\r\n\r\n while (index < segments.length) {\r\n const segment = segments[index]!;\r\n\r\n if (segment.type === 'equal') {\r\n offset += Array.from(segment.text).length;\r\n index += 1;\r\n continue;\r\n }\r\n\r\n if (segment.type === 'delete') {\r\n const next = segments[index + 1];\r\n\r\n // Adjacent delete+insert is a replacement, which is easier for review\r\n // workflows to display than two independent operations.\r\n if (next?.type === 'insert') {\r\n changes.push({\r\n op: 'replaceTextRange',\r\n offset,\r\n oldText: segment.text,\r\n newText: next.text,\r\n });\r\n offset += Array.from(segment.text).length;\r\n index += 2;\r\n continue;\r\n }\r\n\r\n changes.push({\r\n op: 'deleteText',\r\n offset,\r\n oldText: segment.text,\r\n });\r\n offset += Array.from(segment.text).length;\r\n index += 1;\r\n continue;\r\n }\r\n\r\n // Insertions do not advance the old-text offset because no old text is\r\n // consumed by an insertion.\r\n changes.push({\r\n op: 'insertText',\r\n offset,\r\n text: segment.text,\r\n });\r\n index += 1;\r\n }\r\n\r\n return changes;\r\n}\r\n\r\n/** Append a segment, merging it with the previous segment when possible. */\r\nfunction pushSegment(segments: TextDiffSegment[], next: TextDiffSegment): void {\r\n const previous = segments.at(-1);\r\n\r\n if (previous?.type === next.type) {\r\n previous.text += next.text;\r\n return;\r\n }\r\n\r\n segments.push({ ...next });\r\n}\r\n","import { normalizeXml } from './normalize.js';\r\nimport { parseXml } from './parse.js';\r\nimport { diffText } from './text-diff.js';\r\nimport type { XmlDiffOp, XmlDiffOptions, XmlNode } from './types.js';\r\nimport { formatPathSegment, getNodeKey } from './utils.js';\r\n\r\n/**\r\n * Compare two XML inputs and return structured, machine-readable operations.\r\n *\r\n * Inputs can be raw XML strings or pre-parsed `XmlNode` ASTs. Both sides are\r\n * normalized before comparison, so options such as `ignoreWhitespaceText` and\r\n * `ignoreComments` are applied consistently to old and new documents.\r\n *\r\n * The returned operations use absolute paths from the XML root node. The path\r\n * format is intentionally deterministic and readable, for example:\r\n * `/procedure[0]/step[@id=\"s1\"][0]/text()[0]`.\r\n */\r\nexport function diffXml(\r\n oldInput: string | XmlNode,\r\n newInput: string | XmlNode,\r\n options: XmlDiffOptions = {},\r\n): XmlDiffOp[] {\r\n const oldNode = normalizeXml(typeof oldInput === 'string' ? parseXml(oldInput) : oldInput, options);\r\n const newNode = normalizeXml(typeof newInput === 'string' ? parseXml(newInput) : newInput, options);\r\n\r\n const ops: XmlDiffOp[] = [];\r\n diffNode(oldNode, newNode, `/${formatPathSegment(oldNode, 0, options.keyAttrs)}`, options, ops);\r\n return ops;\r\n}\r\n\r\n/** Compare two nodes that are expected to represent the same path. */\r\nfunction diffNode(\r\n oldNode: XmlNode,\r\n newNode: XmlNode,\r\n path: string,\r\n options: XmlDiffOptions,\r\n ops: XmlDiffOp[],\r\n): void {\r\n if (oldNode.type !== newNode.type) {\r\n ops.push({ op: 'replaceNode', path, oldValue: oldNode, newValue: newNode });\r\n return;\r\n }\r\n\r\n if (oldNode.type === 'text' && newNode.type === 'text') {\r\n if (oldNode.text !== newNode.text) {\r\n const textDiff = diffText(oldNode.text, newNode.text);\r\n ops.push({\r\n op: 'replaceText',\r\n path,\r\n oldValue: oldNode.text,\r\n newValue: newNode.text,\r\n changes: textDiff.changes,\r\n segments: textDiff.segments,\r\n });\r\n }\r\n return;\r\n }\r\n\r\n if (oldNode.type === 'comment' && newNode.type === 'comment') {\r\n if (oldNode.text !== newNode.text) {\r\n ops.push({ op: 'replaceNode', path, oldValue: oldNode, newValue: newNode });\r\n }\r\n return;\r\n }\r\n\r\n if (oldNode.type !== 'element' || newNode.type !== 'element') return;\r\n\r\n // Different element names or namespace URIs are treated as whole-node replacement.\r\n // This keeps the first version simple and avoids ambiguous rename semantics.\r\n if (oldNode.name !== newNode.name || oldNode.namespaceURI !== newNode.namespaceURI) {\r\n ops.push({ op: 'replaceNode', path, oldValue: oldNode, newValue: newNode });\r\n return;\r\n }\r\n\r\n diffAttributes(oldNode.attrs, newNode.attrs, path, ops);\r\n diffChildren(oldNode.children, newNode.children, path, options, ops);\r\n}\r\n\r\n/** Compare attribute maps on the same element path. */\r\nfunction diffAttributes(\r\n oldAttrs: Record<string, string>,\r\n newAttrs: Record<string, string>,\r\n path: string,\r\n ops: XmlDiffOp[],\r\n): void {\r\n for (const [name, oldValue] of Object.entries(oldAttrs)) {\r\n const newValue = newAttrs[name];\r\n\r\n if (newValue === undefined) {\r\n ops.push({ op: 'removeAttr', path, name, oldValue });\r\n } else if (newValue !== oldValue) {\r\n ops.push({ op: 'updateAttr', path, name, oldValue, newValue });\r\n }\r\n }\r\n\r\n for (const [name, value] of Object.entries(newAttrs)) {\r\n if (oldAttrs[name] === undefined) {\r\n ops.push({ op: 'addAttr', path, name, value });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Compare child nodes.\r\n *\r\n * If `keyAttrs` is provided and at least one sibling has a key, keyed children\r\n * are aligned by key first. This reduces false positives for document models\r\n * where stable IDs are more meaningful than sibling indexes. Unkeyed children\r\n * still fall back to index-based comparison.\r\n */\r\nfunction diffChildren(\r\n oldChildren: XmlNode[],\r\n newChildren: XmlNode[],\r\n parentPath: string,\r\n options: XmlDiffOptions,\r\n ops: XmlDiffOp[],\r\n): void {\r\n const keyAttrs = options.keyAttrs ?? [];\r\n\r\n if (keyAttrs.length > 0) {\r\n const oldKeyed = new Map<string, { node: XmlNode; index: number }>();\r\n const newKeyed = new Map<string, { node: XmlNode; index: number }>();\r\n\r\n oldChildren.forEach((node, index) => {\r\n const key = getNodeKey(node, keyAttrs);\r\n if (key) oldKeyed.set(key, { node, index });\r\n });\r\n\r\n newChildren.forEach((node, index) => {\r\n const key = getNodeKey(node, keyAttrs);\r\n if (key) newKeyed.set(key, { node, index });\r\n });\r\n\r\n if (oldKeyed.size > 0 || newKeyed.size > 0) {\r\n for (const [key, { node, index }] of oldKeyed) {\r\n const next = newKeyed.get(key);\r\n const childPath = `${parentPath}/${formatPathSegment(node, index, keyAttrs)}`;\r\n\r\n if (!next) {\r\n ops.push({ op: 'removeNode', path: childPath, oldValue: node });\r\n } else {\r\n const newPath = `${parentPath}/${formatPathSegment(next.node, next.index, keyAttrs)}`;\r\n\r\n // Move detection is opt-in because move application changes sibling order.\r\n // Consumers that only need semantic comparison can keep the conservative default.\r\n if (options.detectMoves === true && index !== next.index) {\r\n ops.push({\r\n op: 'moveNode',\r\n path: childPath,\r\n fromPath: childPath,\r\n toPath: newPath,\r\n value: next.node,\r\n });\r\n }\r\n\r\n diffNode(node, next.node, childPath, options, ops);\r\n }\r\n }\r\n\r\n for (const [, { node, index }] of newKeyed) {\r\n const key = getNodeKey(node, keyAttrs);\r\n if (key && !oldKeyed.has(key)) {\r\n const childPath = `${parentPath}/${formatPathSegment(node, index, keyAttrs)}`;\r\n ops.push({ op: 'addNode', path: childPath, value: node });\r\n }\r\n }\r\n\r\n const oldUnkeyed = oldChildren\r\n .map((node, index) => ({ node, index }))\r\n .filter(({ node }) => !getNodeKey(node, keyAttrs));\r\n const newUnkeyed = newChildren\r\n .map((node, index) => ({ node, index }))\r\n .filter(({ node }) => !getNodeKey(node, keyAttrs));\r\n\r\n diffChildrenByIndex(oldUnkeyed, newUnkeyed, parentPath, options, ops);\r\n return;\r\n }\r\n }\r\n\r\n diffChildrenByIndex(\r\n oldChildren.map((node, index) => ({ node, index })),\r\n newChildren.map((node, index) => ({ node, index })),\r\n parentPath,\r\n options,\r\n ops,\r\n );\r\n}\r\n\r\n/** Compare child arrays by their current sibling indexes. */\r\nfunction diffChildrenByIndex(\r\n oldChildren: Array<{ node: XmlNode; index: number }>,\r\n newChildren: Array<{ node: XmlNode; index: number }>,\r\n parentPath: string,\r\n options: XmlDiffOptions,\r\n ops: XmlDiffOp[],\r\n): void {\r\n const max = Math.max(oldChildren.length, newChildren.length);\r\n\r\n for (let index = 0; index < max; index += 1) {\r\n const oldItem = oldChildren[index];\r\n const newItem = newChildren[index];\r\n\r\n if (!oldItem && newItem) {\r\n const childPath = `${parentPath}/${formatPathSegment(newItem.node, newItem.index, options.keyAttrs)}`;\r\n ops.push({ op: 'addNode', path: childPath, value: newItem.node });\r\n continue;\r\n }\r\n\r\n if (oldItem && !newItem) {\r\n const childPath = `${parentPath}/${formatPathSegment(oldItem.node, oldItem.index, options.keyAttrs)}`;\r\n ops.push({ op: 'removeNode', path: childPath, oldValue: oldItem.node });\r\n continue;\r\n }\r\n\r\n if (oldItem && newItem) {\r\n const childPath = `${parentPath}/${formatPathSegment(oldItem.node, oldItem.index, options.keyAttrs)}`;\r\n diffNode(oldItem.node, newItem.node, childPath, options, ops);\r\n }\r\n }\r\n}\r\n","import type { SerializeOptions, XmlNode } from './types.js';\r\nimport { escapeXmlAttr, escapeXmlText } from './utils.js';\r\n\r\n/**\r\n * Serialize a normalized XML AST back to XML text.\r\n *\r\n * The serializer is intentionally small and deterministic. It does not attempt\r\n * to preserve the original lexical formatting of the input XML; instead, it\r\n * serializes the current AST state. Use `pretty` when human-readable nested\r\n * output is preferred.\r\n */\r\nexport function serializeXml(node: XmlNode, options: SerializeOptions = {}): string {\r\n return serializeNode(node, options, 0);\r\n}\r\n\r\n/** Serialize one node recursively. */\r\nfunction serializeNode(node: XmlNode, options: SerializeOptions, level: number): string {\r\n if (node.type === 'text') {\r\n return escapeXmlText(node.text);\r\n }\r\n\r\n if (node.type === 'comment') {\r\n return `<!--${node.text}-->`;\r\n }\r\n\r\n const attrs = Object.entries(node.attrs)\r\n .map(([name, value]) => ` ${name}=\"${escapeXmlAttr(value)}\"`)\r\n .join('');\r\n\r\n if (node.children.length === 0) {\r\n return `${indent(options, level)}<${node.name}${attrs}/>`;\r\n }\r\n\r\n // Keep text-only elements inline even in pretty mode so simple content like\r\n // `<title>Hello</title>` does not become unnecessarily noisy.\r\n if (!options.pretty || node.children.every((child) => child.type === 'text')) {\r\n const children = node.children.map((child) => serializeNode(child, options, level + 1)).join('');\r\n return `${indent(options, level)}<${node.name}${attrs}>${children}</${node.name}>`;\r\n }\r\n\r\n const children = node.children\r\n .map((child) => serializeNode(child, options, level + 1))\r\n .join('\\n');\r\n\r\n return `${indent(options, level)}<${node.name}${attrs}>\\n${children}\\n${indent(\r\n options,\r\n level,\r\n )}</${node.name}>`;\r\n}\r\n\r\n/** Return indentation for a nesting level when pretty output is enabled. */\r\nfunction indent(options: SerializeOptions, level: number): string {\r\n if (!options.pretty) return '';\r\n\r\n return (options.indent ?? ' ').repeat(level);\r\n}\r\n","import { serializeXml } from './serialize.js';\r\nimport type { DiffSummaryItem, FormatDiffOptions, XmlDiffOp, XmlNode } from './types.js';\r\n\r\nexport function formatDiff(ops: XmlDiffOp[], options: FormatDiffOptions & { format: 'markdown' }): string;\r\nexport function formatDiff(ops: XmlDiffOp[], options?: FormatDiffOptions): DiffSummaryItem[];\r\n/**\r\n * Format structured diff operations for humans.\r\n *\r\n * By default, this returns a typed summary array that is easy to consume in UI\r\n * code. With `{ format: 'markdown' }`, it returns a markdown report suitable\r\n * for logs, pull request comments, review notes, or exported change summaries.\r\n */\r\nexport function formatDiff(\r\n ops: XmlDiffOp[],\r\n options: FormatDiffOptions = {},\r\n): DiffSummaryItem[] | string {\r\n if (options.format === 'markdown') {\r\n return toMarkdown(ops);\r\n }\r\n\r\n return ops.map(toSummaryItem);\r\n}\r\n\r\n/** Build a full markdown report from all operations. */\r\nfunction toMarkdown(ops: XmlDiffOp[]): string {\r\n if (ops.length === 0) {\r\n return '# XML Diff\\n\\nNo XML differences.';\r\n }\r\n\r\n return [\r\n '# XML Diff',\r\n '',\r\n `Total changes: ${ops.length}`,\r\n '',\r\n ...ops.flatMap((op, index) => formatMarkdownOp(op, index + 1)),\r\n ].join('\\n');\r\n}\r\n\r\n/** Format one operation as a markdown section. */\r\nfunction formatMarkdownOp(op: XmlDiffOp, index: number): string[] {\r\n switch (op.op) {\r\n case 'addNode':\r\n return [\r\n `## ${index}. Added node`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n '',\r\n codeBlock('xml', serializeForMarkdown(op.value)),\r\n '',\r\n ];\r\n\r\n case 'removeNode':\r\n return [\r\n `## ${index}. Removed node`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n '',\r\n codeBlock('xml', serializeForMarkdown(op.oldValue)),\r\n '',\r\n ];\r\n\r\n case 'replaceNode':\r\n return [\r\n `## ${index}. Replaced node`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n '',\r\n '**Before**',\r\n '',\r\n codeBlock('xml', serializeForMarkdown(op.oldValue)),\r\n '',\r\n '**After**',\r\n '',\r\n codeBlock('xml', serializeForMarkdown(op.newValue)),\r\n '',\r\n ];\r\n\r\n case 'moveNode':\r\n return [\r\n `## ${index}. Moved node`,\r\n '',\r\n `- From: \\`${op.fromPath}\\``,\r\n `- To: \\`${op.toPath}\\``,\r\n '',\r\n codeBlock('xml', serializeForMarkdown(op.value)),\r\n '',\r\n ];\r\n\r\n case 'replaceText':\r\n return [\r\n `## ${index}. Changed text`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n '',\r\n '**Before**',\r\n '',\r\n codeBlock('text', op.oldValue),\r\n '',\r\n '**After**',\r\n '',\r\n codeBlock('text', op.newValue),\r\n '',\r\n '**Text segments**',\r\n '',\r\n ...op.segments.map((segment) => `- ${segment.type}: \\`${escapeInlineCode(segment.text)}\\``),\r\n '',\r\n ];\r\n\r\n case 'addAttr':\r\n return [\r\n `## ${index}. Added attribute`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n `- Name: \\`${op.name}\\``,\r\n `- Value: \\`${escapeInlineCode(op.value)}\\``,\r\n '',\r\n ];\r\n\r\n case 'updateAttr':\r\n return [\r\n `## ${index}. Updated attribute`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n `- Name: \\`${op.name}\\``,\r\n `- Before: \\`${escapeInlineCode(op.oldValue)}\\``,\r\n `- After: \\`${escapeInlineCode(op.newValue)}\\``,\r\n '',\r\n ];\r\n\r\n case 'removeAttr':\r\n return [\r\n `## ${index}. Removed attribute`,\r\n '',\r\n `- Path: \\`${op.path}\\``,\r\n `- Name: \\`${op.name}\\``,\r\n `- Old value: \\`${escapeInlineCode(op.oldValue)}\\``,\r\n '',\r\n ];\r\n }\r\n}\r\n\r\n/** Convert one operation into a typed summary item. */\r\nfunction toSummaryItem(op: XmlDiffOp): DiffSummaryItem {\r\n switch (op.op) {\r\n case 'addNode':\r\n return {\r\n type: 'nodeAdded',\r\n path: op.path,\r\n message: `Added node at ${op.path}`,\r\n after: op.value,\r\n };\r\n\r\n case 'removeNode':\r\n return {\r\n type: 'nodeRemoved',\r\n path: op.path,\r\n message: `Removed node at ${op.path}`,\r\n before: op.oldValue,\r\n };\r\n\r\n case 'replaceNode':\r\n return {\r\n type: 'nodeReplaced',\r\n path: op.path,\r\n message: `Replaced node at ${op.path}`,\r\n before: op.oldValue,\r\n after: op.newValue,\r\n };\r\n\r\n case 'moveNode':\r\n return {\r\n type: 'nodeMoved',\r\n path: op.path,\r\n message: `Moved node from ${op.fromPath} to ${op.toPath}`,\r\n before: op.fromPath,\r\n after: op.toPath,\r\n };\r\n\r\n case 'replaceText':\r\n return {\r\n type: 'textChanged',\r\n path: op.path,\r\n message: `Changed text at ${op.path}`,\r\n before: op.oldValue,\r\n after: op.newValue,\r\n };\r\n\r\n case 'addAttr':\r\n return {\r\n type: 'attrAdded',\r\n path: op.path,\r\n message: `Added attribute ${op.name} at ${op.path}`,\r\n after: op.value,\r\n };\r\n\r\n case 'updateAttr':\r\n return {\r\n type: 'attrUpdated',\r\n path: op.path,\r\n message: `Updated attribute ${op.name} at ${op.path}`,\r\n before: op.oldValue,\r\n after: op.newValue,\r\n };\r\n\r\n case 'removeAttr':\r\n return {\r\n type: 'attrRemoved',\r\n path: op.path,\r\n message: `Removed attribute ${op.name} at ${op.path}`,\r\n before: op.oldValue,\r\n };\r\n }\r\n}\r\n\r\n/** Serialize a node for markdown code blocks, using pretty XML for elements. */\r\nfunction serializeForMarkdown(node: XmlNode): string {\r\n if (node.type === 'text' || node.type === 'comment') {\r\n return serializeXml(node);\r\n }\r\n\r\n return serializeXml(node, {\r\n pretty: true,\r\n });\r\n}\r\n\r\n/** Create a fenced markdown code block and escape nested fences. */\r\nfunction codeBlock(language: string, value: string): string {\r\n return `\\`\\`\\`${language}\\n${escapeCodeFence(value)}\\n\\`\\`\\``;\r\n}\r\n\r\n/** Prevent embedded triple-backticks from breaking the markdown report. */\r\nfunction escapeCodeFence(value: string): string {\r\n return value.replaceAll('```', '`\\u200b``');\r\n}\r\n\r\n/** Escape backticks inside inline-code spans. */\r\nfunction escapeInlineCode(value: string): string {\r\n return value.replaceAll('`', '\\\\`');\r\n}\r\n","import { normalizeXml } from './normalize.js';\r\nimport { parseXml } from './parse.js';\r\nimport { serializeXml } from './serialize.js';\r\nimport type { SerializeOptions, XmlDiffOp, XmlNode } from './types.js';\r\nimport { cloneXmlNode } from './utils.js';\r\n\r\n/** Internal target descriptor used while applying path-based operations. */\r\ntype PatchTarget = {\r\n /** The node selected by the operation path. */\r\n node: XmlNode;\r\n\r\n /** Parent element for non-root targets. Root targets intentionally omit this. */\r\n parent?: Extract<XmlNode, { type: 'element' }>;\r\n\r\n /** Index of `node` inside `parent.children`; root targets use index 0. */\r\n index: number;\r\n};\r\n\r\nexport function patchXml(input: string, ops: XmlDiffOp[], options?: SerializeOptions): string;\r\nexport function patchXml(input: XmlNode, ops: XmlDiffOp[], options?: SerializeOptions): XmlNode;\r\n/**\r\n * Apply structured diff operations to an XML string or AST.\r\n *\r\n * When the input is a string, the result is serialized XML. When the input is an\r\n * `XmlNode`, the result is a patched `XmlNode`. The input is cloned before any\r\n * operation is applied, so callers do not need to worry about accidental\r\n * mutation of their original XML AST.\r\n *\r\n * Patch application uses the absolute path information stored in each operation.\r\n * The current path parser reads numeric `[index]` parts and ignores optional\r\n * key hints such as `[@id=\"s1\"]`; those hints are useful for readability and\r\n * alignment during diffing, while the numeric indexes remain the executable\r\n * addressing component for patching.\r\n */\r\nexport function patchXml(\r\n input: string | XmlNode,\r\n ops: XmlDiffOp[],\r\n options: SerializeOptions = {},\r\n): string | XmlNode {\r\n const root = cloneXmlNode(typeof input === 'string' ? parseXml(input) : input);\r\n\r\n for (const op of ops) {\r\n applyOp(root, op);\r\n }\r\n\r\n const normalized = normalizeXml(root, { sortAttributes: true });\r\n\r\n if (typeof input === 'string') {\r\n return serializeXml(normalized, options);\r\n }\r\n\r\n return normalized;\r\n}\r\n\r\n/** Apply one operation to the mutable cloned root node. */\r\nfunction applyOp(root: XmlNode, op: XmlDiffOp): void {\r\n if (op.op === 'replaceNode' && isRootPath(op.path)) {\r\n Object.assign(root, cloneXmlNode(op.newValue));\r\n return;\r\n }\r\n\r\n // The added node does not exist in the old tree, so resolving op.path first\r\n // would fail. Resolve the parent path instead, then insert at the final index.\r\n if (op.op === 'addNode') {\r\n const parentPath = getParentPath(op.path);\r\n const parent = getTarget(root, parentPath).node;\r\n assertElement(parent, parentPath);\r\n const insertIndex = getLastIndex(op.path);\r\n parent.children.splice(insertIndex, 0, cloneXmlNode(op.value));\r\n return;\r\n }\r\n\r\n if (op.op === 'moveNode') {\r\n moveNode(root, op.fromPath, op.toPath);\r\n return;\r\n }\r\n\r\n const target = getTarget(root, op.path);\r\n\r\n switch (op.op) {\r\n case 'addAttr':\r\n assertElement(target.node, op.path);\r\n target.node.attrs[op.name] = op.value;\r\n break;\r\n\r\n case 'updateAttr':\r\n assertElement(target.node, op.path);\r\n target.node.attrs[op.name] = op.newValue;\r\n break;\r\n\r\n case 'removeAttr':\r\n assertElement(target.node, op.path);\r\n delete target.node.attrs[op.name];\r\n break;\r\n\r\n case 'replaceText':\r\n if (target.node.type !== 'text') {\r\n throw new Error(`Cannot replace text at non-text path: ${op.path}`);\r\n }\r\n target.node.text = op.newValue;\r\n break;\r\n\r\n case 'replaceNode':\r\n if (!target.parent) throw new Error('Cannot replace root node without root replace path.');\r\n target.parent.children[target.index] = cloneXmlNode(op.newValue);\r\n break;\r\n\r\n case 'removeNode':\r\n if (!target.parent) throw new Error('Cannot remove root node.');\r\n target.parent.children.splice(target.index, 1);\r\n break;\r\n }\r\n}\r\n\r\n/** Move an existing node from one absolute path to another. */\r\nfunction moveNode(root: XmlNode, fromPath: string, toPath: string): void {\r\n const source = getTarget(root, fromPath);\r\n\r\n if (!source.parent) {\r\n throw new Error('Cannot move root node.');\r\n }\r\n\r\n const [removed] = source.parent.children.splice(source.index, 1);\r\n if (!removed) {\r\n throw new Error(`Path not found: ${fromPath}`);\r\n }\r\n\r\n const parentPath = getParentPath(toPath);\r\n const targetParent = getTarget(root, parentPath).node;\r\n assertElement(targetParent, parentPath);\r\n\r\n const targetIndex = getLastIndex(toPath);\r\n targetParent.children.splice(targetIndex, 0, removed);\r\n}\r\n\r\n/** Resolve an absolute XML path to a node and, when applicable, its parent. */\r\nfunction getTarget(root: XmlNode, path: string): PatchTarget {\r\n const indexes = getPathIndexes(path);\r\n\r\n if (indexes.length === 0) {\r\n return {\r\n node: root,\r\n index: 0,\r\n };\r\n }\r\n\r\n let current = root;\r\n let parent: Extract<XmlNode, { type: 'element' }> | undefined;\r\n let currentIndex = 0;\r\n\r\n // The first numeric index belongs to the root path segment. Since `root` is\r\n // already selected, traversal starts from the second index.\r\n for (const index of indexes.slice(1)) {\r\n assertElement(current, path);\r\n parent = current;\r\n currentIndex = index;\r\n\r\n const child = current.children[index];\r\n if (!child) {\r\n throw new Error(`Path not found: ${path}`);\r\n }\r\n\r\n current = child;\r\n }\r\n\r\n const result: PatchTarget = {\r\n node: current,\r\n index: currentIndex,\r\n };\r\n\r\n if (parent) {\r\n result.parent = parent;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/** Extract all numeric `[index]` parts from a path. */\r\nfunction getPathIndexes(path: string): number[] {\r\n const matches = path.match(/\\[(\\d+)\\]/g) ?? [];\r\n return matches.map((match) => Number.parseInt(match.slice(1, -1), 10));\r\n}\r\n\r\n/** Return the final numeric path index, usually the insertion or target index. */\r\nfunction getLastIndex(path: string): number {\r\n const indexes = getPathIndexes(path);\r\n const index = indexes.at(-1);\r\n\r\n if (index === undefined) {\r\n throw new Error(`Path has no numeric index: ${path}`);\r\n }\r\n\r\n return index;\r\n}\r\n\r\n/** Return the absolute parent path for a node path. */\r\nfunction getParentPath(path: string): string {\r\n const parts = path.split('/').filter(Boolean);\r\n\r\n if (parts.length <= 1) {\r\n return path;\r\n }\r\n\r\n return `/${parts.slice(0, -1).join('/')}`;\r\n}\r\n\r\n/** A root path has exactly one path segment, for example `/root[0]`. */\r\nfunction isRootPath(path: string): boolean {\r\n return path.split('/').filter(Boolean).length === 1;\r\n}\r\n\r\n/** Type guard used before mutating element-only fields such as attrs/children. */\r\nfunction assertElement(node: XmlNode, path: string): asserts node is Extract<XmlNode, { type: 'element' }> {\r\n if (node.type !== 'element') {\r\n throw new Error(`Expected element node at path: ${path}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["oldIndex","newIndex","children"]}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "xml-diff-kit",
3
+ "version": "0.1.0",
4
+ "description": "A TypeScript toolkit for parsing, normalizing, diffing, patching, and formatting XML document changes.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "vndmea",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/vndmea/xml-diff-kit.git"
11
+ },
12
+ "homepage": "https://github.com/vndmea/xml-diff-kit#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/vndmea/xml-diff-kit/issues"
15
+ },
16
+ "keywords": [
17
+ "xml",
18
+ "diff",
19
+ "patch",
20
+ "typescript",
21
+ "structured-diff",
22
+ "xmldiff"
23
+ ],
24
+ "sideEffects": false,
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js",
35
+ "require": "./dist/index.cjs"
36
+ }
37
+ },
38
+ "scripts": {
39
+ "clean": "rimraf dist coverage",
40
+ "build": "tsup",
41
+ "typecheck": "tsc --noEmit",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
44
+ "coverage": "vitest run --coverage",
45
+ "lint": "eslint .",
46
+ "prepublishOnly": "npm run clean && npm run lint && npm run typecheck && npm test && npm run build"
47
+ },
48
+ "dependencies": {
49
+ "@xmldom/xmldom": "^0.8.10"
50
+ },
51
+ "devDependencies": {
52
+ "@eslint/js": "^9.0.0",
53
+ "@types/node": "^22.0.0",
54
+ "@vitest/coverage-v8": "^3.0.0",
55
+ "eslint": "^9.0.0",
56
+ "rimraf": "^6.0.0",
57
+ "tsup": "^8.0.0",
58
+ "typescript": "^5.0.0",
59
+ "typescript-eslint": "^8.0.0",
60
+ "vitest": "^3.0.0"
61
+ },
62
+ "engines": {
63
+ "node": ">=18"
64
+ }
65
+ }