@office-open/docx 0.10.15 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -17
- package/dist/index.d.mts +3774 -33
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +16469 -530
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -34
- package/dist/chart.d.mts +0 -1
- package/dist/chart.mjs +0 -2
- package/dist/comments-D_flVfxw.mjs +0 -8509
- package/dist/comments-D_flVfxw.mjs.map +0 -1
- package/dist/context-DLmSgNzb.mjs +0 -4536
- package/dist/context-DLmSgNzb.mjs.map +0 -1
- package/dist/core-properties-BLnZI4Tr.d.mts +0 -4004
- package/dist/core-properties-BLnZI4Tr.d.mts.map +0 -1
- package/dist/document-attributes-C6PDT-ap.mjs +0 -60
- package/dist/document-attributes-C6PDT-ap.mjs.map +0 -1
- package/dist/drawingml.d.mts +0 -1
- package/dist/drawingml.mjs +0 -2
- package/dist/generate-BNjgksa0.mjs +0 -535
- package/dist/generate-BNjgksa0.mjs.map +0 -1
- package/dist/generate.d.mts +0 -10
- package/dist/generate.d.mts.map +0 -1
- package/dist/generate.mjs +0 -2
- package/dist/parse-CgAxzk5K.mjs +0 -2115
- package/dist/parse-CgAxzk5K.mjs.map +0 -1
- package/dist/parse.d.mts +0 -2
- package/dist/parse.mjs +0 -2
- package/dist/patch/index.d.mts +0 -47
- package/dist/patch/index.d.mts.map +0 -1
- package/dist/patch/index.mjs +0 -416
- package/dist/patch/index.mjs.map +0 -1
- package/dist/smartart.d.mts +0 -1
- package/dist/smartart.mjs +0 -2
package/dist/patch/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/patch/from-docx.ts","../../src/patch/patch-detector.ts"],"sourcesContent":["import { TargetModeType } from \"@office-open/core\";\nimport {\n DOCX_NS,\n OoxmlMimeType,\n appendContentType,\n appendOverride,\n appendRelationship,\n applyCorePropertiesOverride,\n createReplacer,\n getNextRelationshipIndex,\n getReferencedMedia,\n nextNumericId,\n replaceImagePlaceholders,\n strFromU8,\n toJson,\n unzipSync,\n zipAndConvert,\n} from \"@office-open/core\";\nimport type {\n BasePatchOptions,\n CorePropertiesOptions,\n OutputByType,\n OutputType,\n} from \"@office-open/core\";\nimport { toUint8Array } from \"@office-open/core\";\nimport { escapeXml, js2xml, xml2js } from \"@office-open/xml\";\nimport type { Element } from \"@office-open/xml\";\nimport { commentsDesc } from \"@parts/comments\";\nimport { DocumentAttributeNamespaces } from \"@parts/document\";\nimport {\n stringifyChildDispatch,\n stringifyParagraphInline,\n stringifyRunInline,\n} from \"@parts/inline\";\nimport type { ParagraphChild } from \"@parts/paragraph/paragraph\";\nimport type { ParagraphOptions } from \"@parts/paragraph/paragraph\";\nimport type { CommentOptions } from \"@parts/paragraph/run/comment-run\";\nimport type { RunOptions } from \"@parts/paragraph/run/run\";\nimport { tableDesc } from \"@parts/table/descriptor\";\nimport type { TableOptions } from \"@parts/table/table\";\nimport { Media } from \"@shared/media\";\nimport type { MediaData } from \"@shared/media/data\";\nimport type { SectionChild } from \"@shared/section\";\n\nimport type { BodyContext } from \"../context\";\nimport type { ViewWrapper } from \"../context\";\n\n/** Reusable TextEncoder (stateless, safe to share). */\nconst encoder = new TextEncoder();\n\nconst COMMENTS_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments\";\nconst COMMENTS_CONTENT_TYPE =\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml\";\n\n/** A comment injected by patch — same as CommentOptions but without an id\n * (the patch assigns continuation ids). */\nexport type PatchComment = Omit<CommentOptions, \"id\">;\n\n/** A comment request resolved to an id and an anchor (paragraph index or placeholder). */\ninterface AssignedComment {\n id: number;\n anchor: { kind: \"paragraph\"; index: number } | { kind: \"placeholder\"; key: string };\n options: PatchComment;\n}\n\n/**\n * Document patching module for modifying existing .docx files.\n *\n * Uses compile-path stringifiers (zero class instantiation) to serialize\n * patch content — no Formatter, no XmlComponent instances.\n *\n * @module\n */\n\n// ── Patch content stringification ──\n\n/**\n * Lightweight BodyContext adapter for patch serialization.\n * Captures hyperlink and image relationships for post-processing.\n */\nfunction createPatchContext(\n file: { media: Media<MediaData> },\n hyperlinkSink: Array<{ id: string; link: string }>,\n): BodyContext {\n return {\n fileData: file as unknown as BodyContext[\"fileData\"],\n file: file as unknown as BodyContext[\"file\"],\n viewWrapper: {\n relationships: {\n addRelationship: (linkId: string, _type: string, target: string, _mode?: string) => {\n hyperlinkSink.push({ id: linkId, link: target });\n },\n relationshipCount: 0,\n },\n } as unknown as BodyContext[\"viewWrapper\"],\n stringifyChild: () => \"\",\n addRelationship: () => \"\",\n addMedia: () => \"\",\n };\n}\n\n/**\n * Serialize a patch child (SectionChild / ParagraphChild / string) into XML\n * elements via the compile-path stringifiers. Shared by the placeholder\n * replacer and body-level `append`. Relies on the module-level\n * {@link currentPatchCtx} for relationship/media sinks.\n */\nconst formatChildElement = (child: unknown): Element[] => {\n let xmlStr: string;\n\n if (typeof child === \"string\") {\n // Plain string → simple run\n xmlStr = `<w:r><w:t xml:space=\"preserve\">${escapeXml(child)}</w:t></w:r>`;\n } else if (typeof child === \"object\" && child !== null) {\n const obj = child as Record<string, unknown>;\n // SectionChild level (paragraph / table) — for DOCUMENT patches and append\n if (\"paragraph\" in obj) {\n xmlStr = stringifyParagraphInline(obj.paragraph as ParagraphOptions, currentPatchCtx);\n } else if (\"table\" in obj) {\n xmlStr = tableDesc.stringify(obj.table as TableOptions, currentPatchCtx) ?? \"\";\n } else {\n // ParagraphChild level — for PARAGRAPH patches\n // Try compile-path JSON child dispatch first\n const jr = stringifyChildDispatch(child as ParagraphChild, currentPatchCtx);\n if (jr !== undefined) {\n xmlStr = Array.isArray(jr) ? jr.join(\"\") : jr;\n } else {\n // RunOptions (plain objects with text/children/bold/etc.)\n xmlStr = stringifyRunInline(child as RunOptions, currentPatchCtx);\n }\n }\n } else {\n xmlStr = \"<w:r/>\";\n }\n\n const jsonObj = xml2js(xmlStr, { captureSpacesBetweenElements: true });\n const rootEl = jsonObj.elements?.[0];\n // xml2js yields a single root element for a well-formed fragment\n return rootEl ? [rootEl] : [];\n};\n\nconst docxReplacer = createReplacer({\n ns: DOCX_NS,\n formatChild: formatChildElement,\n});\n\n/**\n * Splice block-level children into `<w:body>` before the trailing `<w:sectPr>`\n * (the final section properties). If the body has no trailing sectPr, append at\n * the end. Reuses {@link formatChildElement} so the same serialization and\n * relationship/media sinks apply as placeholder patches.\n */\nconst appendToBody = (root: Element, children: SectionChild[]): void => {\n const docEl = root.elements?.find((e) => e.name === \"w:document\");\n const body = docEl?.elements?.find((e) => e.name === \"w:body\");\n if (!body) return;\n const els = body.elements ?? (body.elements = []);\n const newEls: Element[] = [];\n for (const child of children) {\n newEls.push(...formatChildElement(child));\n }\n // Insert before the trailing <w:sectPr>; otherwise at the end.\n let insertAt = els.length;\n for (let i = els.length - 1; i >= 0; i--) {\n const el = els[i];\n if (el && el.name === \"w:sectPr\") {\n insertAt = i;\n break;\n }\n }\n els.splice(insertAt, 0, ...newEls);\n};\n\n/** Current patch context — set per file in the main loop. */\nlet currentPatchCtx: BodyContext;\n\n/**\n * A patch operation: replace a placeholder with either inline run-level\n * content (`type: \"paragraph\"`) or block-level content (`type: \"document\"`).\n *\n * The `type` is a bare string literal (no PatchType enum) — the core\n * replacer already discriminates on `patch.type`.\n */\nexport type Patch =\n | { type: \"paragraph\"; children: (string | RunOptions | ParagraphChild)[] }\n | { type: \"document\"; children: SectionChild[] };\n\ninterface ImageRelationshipAddition {\n key: string;\n mediaDatas: { fileName: string }[];\n}\n\ninterface HyperlinkRelationshipAddition {\n key: string;\n hyperlink: { id: string; link: string };\n}\n\nexport interface PatchDocumentOptions<\n T extends OutputType = OutputType,\n> extends BasePatchOptions<T> {\n /** Placeholder substitutions: `{{key}}` (per delimiters) → patch content. */\n placeholders?: Readonly<Record<string, Patch>>;\n /** Literal find/replace: the find string → patch content (no delimiters added). */\n findReplace?: Readonly<Record<string, Patch>>;\n /** Core-properties metadata override (merged over the existing docProps/core.xml). */\n coreProperties?: Partial<CorePropertiesOptions>;\n keepOriginalStyles?: boolean;\n recursive?: boolean;\n /** Block-level content appended to the document body, before the final section break. */\n append?: SectionChild[];\n /**\n * Comments to inject. `paragraphs` anchors a comment to the Nth body paragraph\n * (0-based, wraps the whole paragraph); `placeholders` anchors to the run\n * containing a {{key}} (wrapped before placeholder substitution). Ids are\n * continued from any existing word/comments.xml; entries are merged in.\n */\n comments?: {\n paragraphs?: Readonly<Record<number, PatchComment[]>>;\n placeholders?: Readonly<Record<string, PatchComment[]>>;\n };\n}\n\nconst UTF16LE = new Uint8Array([0xff, 0xfe]);\nconst UTF16BE = new Uint8Array([0xfe, 0xff]);\n\nconst compareByteArrays = (a: Uint8Array, b: Uint8Array): boolean => {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n};\n\n/**\n * Patches an existing .docx document by replacing placeholders with new content.\n *\n * @publicApi\n */\nexport const patchDocument = async <T extends OutputType = OutputType>({\n outputType,\n data,\n placeholders,\n findReplace,\n coreProperties,\n append,\n comments,\n keepOriginalStyles = true,\n placeholderDelimiters = { end: \"}}\", start: \"{{\" } as const,\n recursive = true,\n}: PatchDocumentOptions<T>): Promise<OutputByType[T]> => {\n const zipContent = unzipSync(toUint8Array(data));\n const contexts = new Map<string, BodyContext>();\n const media = new Media<MediaData>();\n const file = { media } as BodyContext[\"file\"];\n\n // Resolve comment ids by continuation from any existing word/comments.xml.\n const assignedComments = buildAssignedComments(zipContent, comments);\n\n const map = new Map<string, Element>();\n\n const imageRelationshipAdditions: ImageRelationshipAddition[] = [];\n const hyperlinkRelationshipAdditions: HyperlinkRelationshipAddition[] = [];\n let hasMedia = false;\n\n const binaryContentMap = new Map<string, Uint8Array>();\n\n for (const [key, value] of Object.entries(zipContent)) {\n const startBytes = value.slice(0, 2);\n if (compareByteArrays(startBytes, UTF16LE) || compareByteArrays(startBytes, UTF16BE)) {\n binaryContentMap.set(key, value);\n continue;\n }\n\n if (!key.endsWith(\".xml\") && !key.endsWith(\".rels\")) {\n binaryContentMap.set(key, value);\n continue;\n }\n\n const json = toJson(strFromU8(value));\n\n if (key === \"word/document.xml\") {\n const document = json.elements?.find((i) => i.name === \"w:document\");\n if (document && document.attributes) {\n for (const ns of [\"mc\", \"wp\", \"r\", \"w15\", \"m\"] as const) {\n document.attributes[`xmlns:${ns}`] = DocumentAttributeNamespaces[ns];\n }\n document.attributes[\"mc:Ignorable\"] =\n `${document.attributes[\"mc:Ignorable\"] || \"\"} w15`.trim();\n }\n }\n\n if (key.startsWith(\"word/\") && !key.endsWith(\".xml.rels\")) {\n const hyperlinkSink: Array<{ id: string; link: string }> = [];\n\n const context: BodyContext = {\n fileData: file,\n file,\n viewWrapper: {\n relationships: {\n addRelationship: (\n linkId: string,\n _: string,\n target: string,\n __: (typeof TargetModeType)[keyof typeof TargetModeType],\n ) => {\n hyperlinkRelationshipAdditions.push({\n hyperlink: {\n id: linkId,\n link: target,\n },\n key,\n });\n },\n },\n } as unknown as ViewWrapper,\n stringifyChild: () => \"\",\n addRelationship: () => \"\",\n addMedia: () => \"\",\n };\n contexts.set(key, context);\n\n if (!placeholderDelimiters?.start.trim() || !placeholderDelimiters?.end.trim()) {\n throw new Error(\"Both start and end delimiters must be non-empty strings.\");\n }\n\n const { start, end } = placeholderDelimiters;\n\n // Create compile-path context for stringifying patch children\n const patchCtx = createPatchContext(file, hyperlinkSink);\n currentPatchCtx = patchCtx;\n\n // Anchor placeholder comments BEFORE substitution, wrapping the {{key}} run.\n if (key === \"word/document.xml\") {\n for (const ac of assignedComments) {\n if (ac.anchor.kind === \"placeholder\") {\n wrapPlaceholderComment(json, `${start}${ac.anchor.key}${end}`, ac.id);\n }\n }\n }\n\n // Build (find-text → patch) entries. Placeholders wrap the key in\n // delimiters; findReplace uses the literal key. Both share one engine.\n const entries: Array<{ find: string; patch: Patch }> = [];\n if (placeholders) {\n for (const [key, value] of Object.entries(placeholders)) {\n entries.push({ find: `${start}${key}${end}`, patch: value });\n }\n }\n if (findReplace) {\n for (const [key, value] of Object.entries(findReplace)) {\n entries.push({ find: key, patch: value });\n }\n }\n\n for (const { find: patchText, patch: patchValue } of entries) {\n while (true) {\n const { didFindOccurrence } = docxReplacer({\n context,\n json,\n keepOriginalStyles,\n patch: patchValue,\n patchText,\n });\n if (!recursive || !didFindOccurrence) {\n break;\n }\n }\n }\n\n // Append block-level children to the document body before the final sectPr.\n if (append && append.length > 0 && key === \"word/document.xml\") {\n appendToBody(json, append);\n }\n\n // Anchor paragraph comments AFTER body edits, wrapping the Nth paragraph.\n if (key === \"word/document.xml\") {\n for (const ac of assignedComments) {\n if (ac.anchor.kind === \"paragraph\") {\n wrapParagraphComment(json, ac.anchor.index, ac.id);\n }\n }\n }\n\n // Flush hyperlink relationships captured by the compile-path context\n for (const hl of hyperlinkSink) {\n hyperlinkRelationshipAdditions.push({\n hyperlink: { id: hl.id, link: hl.link },\n key,\n });\n }\n\n const mediaDatas = getReferencedMedia(JSON.stringify(json), media.array);\n if (mediaDatas.length > 0) {\n hasMedia = true;\n imageRelationshipAdditions.push({\n key,\n mediaDatas,\n });\n }\n }\n\n map.set(key, json);\n }\n\n // Merge injected comments into word/comments.xml + wire rels + content types.\n if (assignedComments.length > 0) {\n mergeCommentsPart(map, assignedComments, file);\n }\n\n for (const { key, mediaDatas } of imageRelationshipAdditions) {\n const relationshipKey = `word/_rels/${key.split(\"/\").pop()}.rels`;\n const relationshipsJson = map.get(relationshipKey) ?? createRelationshipFile();\n map.set(relationshipKey, relationshipsJson);\n\n const index = getNextRelationshipIndex(relationshipsJson);\n const newJson = replaceImagePlaceholders(\n JSON.stringify(map.get(key)),\n mediaDatas,\n index,\n \"plain\",\n );\n map.set(key, JSON.parse(newJson) as Element);\n\n for (const [i, media] of mediaDatas.entries()) {\n const { fileName } = media;\n appendRelationship(\n relationshipsJson,\n index + i,\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\",\n `media/${fileName}`,\n );\n }\n }\n\n for (const { key, hyperlink } of hyperlinkRelationshipAdditions) {\n const relationshipKey = `word/_rels/${key.split(\"/\").pop()}.rels`;\n\n const relationshipsJson = map.get(relationshipKey) ?? createRelationshipFile();\n map.set(relationshipKey, relationshipsJson);\n\n appendRelationship(\n relationshipsJson,\n hyperlink.id,\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink\",\n hyperlink.link,\n TargetModeType.EXTERNAL,\n );\n }\n\n if (hasMedia) {\n const contentTypesJson = map.get(\"[Content_Types].xml\");\n\n if (!contentTypesJson) {\n throw new Error(\"Could not find content types file\");\n }\n\n appendContentType(contentTypesJson, \"image/png\", \"png\");\n appendContentType(contentTypesJson, \"image/jpeg\", \"jpeg\");\n appendContentType(contentTypesJson, \"image/jpeg\", \"jpg\");\n appendContentType(contentTypesJson, \"image/bmp\", \"bmp\");\n appendContentType(contentTypesJson, \"image/gif\", \"gif\");\n appendContentType(contentTypesJson, \"image/svg+xml\", \"svg\");\n }\n\n const files: Record<string, Uint8Array> = {};\n const XML_DECL = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>';\n\n for (const [key, value] of map) {\n files[key] =\n key === \"docProps/core.xml\" && coreProperties\n ? encoder.encode(XML_DECL + applyCorePropertiesOverride(value, coreProperties))\n : encoder.encode(js2xml(value));\n }\n\n for (const [key, value] of binaryContentMap) {\n files[key] = value;\n }\n\n for (const { data: mediaData, fileName } of media.array) {\n files[`word/media/${fileName}`] =\n mediaData instanceof Uint8Array ? mediaData : new Uint8Array(mediaData);\n }\n\n return await zipAndConvert(files, outputType, OoxmlMimeType.DOCX);\n};\n\nconst createRelationshipFile = (): Element => ({\n declaration: {\n attributes: {\n encoding: \"UTF-8\",\n standalone: \"yes\",\n version: \"1.0\",\n },\n },\n elements: [\n {\n attributes: {\n xmlns: \"http://schemas.openxmlformats.org/package/2006/relationships\",\n },\n elements: [],\n name: \"Relationships\",\n type: \"element\",\n },\n ],\n});\n\n/** Build a bare OOXML element node with attributes and no children. */\nfunction makeElement(name: string, attributes: Record<string, string> = {}): Element {\n return { type: \"element\", name, attributes, elements: [] };\n}\n\n/** A `<w:r>` carrying a `<w:commentReference>` (CommentReference run style). */\nfunction commentReferenceRun(id: number): Element {\n // xml2js yields a single root <w:r> for this well-formed fragment\n return xml2js(\n `<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"${id}\"/></w:r>`,\n ).elements![0]!;\n}\n\n/** Next continuation id for an appended `<w:comment>` (-1 seed → 0 when none). */\nfunction nextCommentId(commentsPart: Element | undefined): number {\n const root = commentsPart?.elements?.find((e) => e.name === \"w:comments\");\n return nextNumericId(root, \"w:comment\", \"w:id\", -1);\n}\n\n/** Assign continuation ids to every requested comment anchor. */\nfunction buildAssignedComments(\n zipContent: Record<string, Uint8Array>,\n comments: PatchDocumentOptions[\"comments\"],\n): AssignedComment[] {\n if (!comments) return [];\n const raw = zipContent[\"word/comments.xml\"];\n let nextId = raw ? nextCommentId(toJson(strFromU8(raw))) : 0;\n const assigned: AssignedComment[] = [];\n if (comments.placeholders) {\n for (const [key, list] of Object.entries(comments.placeholders)) {\n for (const options of list) {\n assigned.push({ id: nextId++, anchor: { kind: \"placeholder\", key }, options });\n }\n }\n }\n if (comments.paragraphs) {\n for (const [indexStr, list] of Object.entries(comments.paragraphs)) {\n const index = Number(indexStr);\n for (const options of list) {\n assigned.push({ id: nextId++, anchor: { kind: \"paragraph\", index }, options });\n }\n }\n }\n return assigned;\n}\n\n/** Wrap the Nth body paragraph with comment range markers + a reference run. */\nfunction wrapParagraphComment(json: Element, index: number, commentId: number): void {\n const body = json.elements\n ?.find((e) => e.name === \"w:document\")\n ?.elements?.find((e) => e.name === \"w:body\");\n if (!body) return;\n const paragraphs = (body.elements ?? []).filter((e) => e.name === \"w:p\");\n const target = paragraphs[index];\n if (!target) {\n throw new Error(`patchDocument: no paragraph at index ${index} to comment`);\n }\n const els = target.elements ?? (target.elements = []);\n const start = makeElement(\"w:commentRangeStart\", { \"w:id\": String(commentId) });\n const end = makeElement(\"w:commentRangeEnd\", { \"w:id\": String(commentId) });\n // Insert start after a leading <w:pPr> (or at the head); end + ref at the tail.\n const first = els[0];\n const insertAt = first && first.name === \"w:pPr\" ? 1 : 0;\n els.splice(insertAt, 0, start);\n els.push(end, commentReferenceRun(commentId));\n}\n\n/** Wrap the first run whose `<w:t>` contains the placeholder with comment markers. */\nfunction wrapPlaceholderComment(json: Element, placeholder: string, commentId: number): void {\n const body = json.elements\n ?.find((e) => e.name === \"w:document\")\n ?.elements?.find((e) => e.name === \"w:body\");\n if (!body) return;\n for (const p of body.elements ?? []) {\n if (p.name !== \"w:p\") continue;\n const els = p.elements ?? [];\n for (const [i, el] of els.entries()) {\n if (el.name !== \"w:r\") continue;\n const t = (el.elements ?? []).find((e) => e.name === \"w:t\");\n const text = t?.elements?.[0]?.text;\n if (typeof text === \"string\" && text.includes(placeholder)) {\n els.splice(i, 0, makeElement(\"w:commentRangeStart\", { \"w:id\": String(commentId) }));\n els.splice(\n i + 2,\n 0,\n makeElement(\"w:commentRangeEnd\", { \"w:id\": String(commentId) }),\n commentReferenceRun(commentId),\n );\n return; // only the first occurrence\n }\n }\n }\n}\n\n/**\n * Merge assigned comments into word/comments.xml (appending to an existing part\n * or creating one) and wire document.xml.rels + content types when newly added.\n */\nfunction mergeCommentsPart(\n map: Map<string, Element>,\n assigned: AssignedComment[],\n file: { media: Media<MediaData> },\n): void {\n const newOpts: CommentOptions[] = assigned.map((ac) => ({ id: ac.id, ...ac.options }));\n const ctx = createPatchContext(file, []);\n const newXml = commentsDesc.stringify({ children: newOpts }, ctx) ?? \"\";\n const existingEl = map.get(\"word/comments.xml\");\n const wasNew = !existingEl;\n\n if (existingEl) {\n // Append new <w:comment> elements to the existing <w:comments> root.\n const existingRoot = existingEl.elements?.find((e) => e.name === \"w:comments\");\n const newRoot = xml2js(newXml).elements?.find((e) => e.name === \"w:comments\");\n existingRoot?.elements?.push(...(newRoot?.elements ?? []));\n } else {\n map.set(\n \"word/comments.xml\",\n toJson(`<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${newXml}`),\n );\n }\n\n if (wasNew) {\n const relsKey = \"word/_rels/document.xml.rels\";\n const relsJson = map.get(relsKey) ?? createRelationshipFile();\n map.set(relsKey, relsJson);\n appendRelationship(\n relsJson,\n getNextRelationshipIndex(relsJson),\n COMMENTS_REL_TYPE,\n \"comments.xml\",\n );\n }\n\n // Content types — ensure the comments Override exists (deduped). An existing\n // comments part normally already declares it, but defend against incomplete templates.\n const contentTypes = map.get(\"[Content_Types].xml\");\n if (contentTypes) {\n appendOverride(contentTypes, \"/word/comments.xml\", COMMENTS_CONTENT_TYPE);\n }\n}\n","/**\n * Patch detector for discovering placeholders in document templates.\n *\n * @module\n */\nimport { DOCX_NS, createTraverser, strFromU8, toJson, unzipSync } from \"@office-open/core\";\nimport { toUint8Array } from \"@office-open/core\";\nimport type { DataType } from \"@office-open/core\";\n\n/**\n * Options for patch detection.\n *\n * @property data - The document template to scan for placeholders\n */\ninterface PatchDetectorOptions {\n data: DataType;\n}\n\n/**\n * Detects all placeholders present in a document template.\n *\n * Scans through all XML content in a .docx file to find placeholder text\n * enclosed in delimiters (default: {{placeholder}}). This is useful for\n * discovering what patches a template expects before performing replacement.\n *\n * @param options - Patch detector configuration\n * @returns Array of placeholder keys found in the document\n *\n * @example\n * ```typescript\n * const placeholders = await patchDetector({ data: templateBuffer });\n * // Returns: [\"name\", \"date\", \"address\"] if template contains {{name}}, {{date}}, {{address}}\n *\n * // Use detected placeholders to create patches\n * const patches = {};\n * for (const key of placeholders) {\n * patches[key] = {\n * type: \"paragraph\",\n * children: [new TextRun(getUserData(key))],\n * };\n * });\n * ```\n */\nexport const patchDetector = async ({ data }: PatchDetectorOptions): Promise<string[]> => {\n const zipContent = unzipSync(toUint8Array(data));\n const patches = new Set<string>();\n\n for (const [key, value] of Object.entries(zipContent)) {\n if (!key.endsWith(\".xml\") && !key.endsWith(\".rels\")) {\n continue;\n }\n if (key.startsWith(\"word/\") && !key.endsWith(\".xml.rels\")) {\n const json = toJson(strFromU8(value));\n const { traverse } = createTraverser(DOCX_NS);\n for (const p of traverse(json)) {\n for (const patch of findPatchKeys(p.text)) {\n patches.add(patch);\n }\n }\n }\n }\n return [...patches];\n};\n\n/**\n * Extracts placeholder keys from text using regex pattern.\n *\n * @param text - Text to search for placeholders\n * @returns Array of placeholder keys (without delimiters)\n */\nconst findPatchKeys = (text: string): string[] => {\n const pattern = /(?<=\\{\\{).+?(?=\\}\\})/gs;\n return text.match(pattern) ?? [];\n};\n"],"mappings":"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"}
|
package/dist/smartart.d.mts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "@office-open/core/smartart";
|
package/dist/smartart.mjs
DELETED