pptx-ts 4.0.0 → 4.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.
- package/README.md +147 -114
- package/dist/{autopage-odPz7zZO.js → autopage-D4kyVp11.js} +5 -5
- package/dist/{autopage-odPz7zZO.js.map → autopage-D4kyVp11.js.map} +1 -1
- package/dist/{body-insets-Dw_BeWD_.js → body-insets-kVHmjGc6.js} +2 -2
- package/dist/{body-insets-Dw_BeWD_.js.map → body-insets-kVHmjGc6.js.map} +1 -1
- package/dist/browser.d.ts +7 -7
- package/dist/browser.js +5 -5
- package/dist/{clip-Bl01BPcN.d.ts → clip-DHDlnHUq.d.ts} +2 -2
- package/dist/{clip-Bl01BPcN.d.ts.map → clip-DHDlnHUq.d.ts.map} +1 -1
- package/dist/{diagnostics-D8ot4Ei7.d.ts → diagnostics-DiMmBU8P.d.ts} +6 -6
- package/dist/{diagnostics-D8ot4Ei7.d.ts.map → diagnostics-DiMmBU8P.d.ts.map} +1 -1
- package/dist/{embedded-fonts-DarT9aoa.d.ts → embedded-fonts-CI_YGW2d.d.ts} +2 -2
- package/dist/{embedded-fonts-DarT9aoa.d.ts.map → embedded-fonts-CI_YGW2d.d.ts.map} +1 -1
- package/dist/{entry-compose-DCnvBZz2.d.ts → entry-compose-6hF9aTmT.d.ts} +19 -17
- package/dist/{entry-compose-DCnvBZz2.d.ts.map → entry-compose-6hF9aTmT.d.ts.map} +1 -1
- package/dist/{enums-BUKTUB6V.d.ts → enums-DQRpVOLh.d.ts} +3 -3
- package/dist/{enums-BUKTUB6V.d.ts.map → enums-DQRpVOLh.d.ts.map} +1 -1
- package/dist/{errors-C4oENPcu.js → errors-Da2nXCJm.js} +6 -6
- package/dist/{errors-C4oENPcu.js.map → errors-Da2nXCJm.js.map} +1 -1
- package/dist/families.d.ts +6 -6
- package/dist/families.js +2 -2
- package/dist/{fit-Cb7naFj6.js → fit-CcXbg__l.js} +10 -10
- package/dist/{fit-Cb7naFj6.js.map → fit-CcXbg__l.js.map} +1 -1
- package/dist/{font-metrics-v5fn7s7e.d.ts → font-metrics-CBGmhLo0.d.ts} +6 -6
- package/dist/{font-metrics-v5fn7s7e.d.ts.map → font-metrics-CBGmhLo0.d.ts.map} +1 -1
- package/dist/{grid-DikTjFey.js → grid-9B2w5EaY.js} +2 -2
- package/dist/{grid-DikTjFey.js.map → grid-9B2w5EaY.js.map} +1 -1
- package/dist/{html-dom-Iuog2wdK.js → html-dom-DvJmuHt2.js} +10 -10
- package/dist/html-dom-DvJmuHt2.js.map +1 -0
- package/dist/html.d.ts +3 -3
- package/dist/html.js +2 -2
- package/dist/{image-size-CvN2iCA4.js → image-size-DwDbakcl.js} +64 -5
- package/dist/image-size-DwDbakcl.js.map +1 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +3 -3
- package/dist/inspect.d.ts +4 -4
- package/dist/inspect.js +4 -4
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js +1 -1
- package/dist/measure.d.ts +3 -3
- package/dist/measure.js +2 -2
- package/dist/node.d.ts +7 -7
- package/dist/node.js +3 -3
- package/dist/{notes-Dh12JAbn.js → notes-BcT571R4.js} +19 -18
- package/dist/notes-BcT571R4.js.map +1 -0
- package/dist/options-internal-WqgMf720.js.map +1 -1
- package/dist/{package-J49Ck6S2.d.ts → package-KoEgVwII.d.ts} +6 -2
- package/dist/{package-J49Ck6S2.d.ts.map → package-KoEgVwII.d.ts.map} +1 -1
- package/dist/{pres-C6qgOFAa.d.ts → pres-BA9_lJbY.d.ts} +32 -12
- package/dist/pres-BA9_lJbY.d.ts.map +1 -0
- package/dist/{presentation-DGYlAWhl.js → presentation-Cyl74rq2.js} +70 -35
- package/dist/presentation-Cyl74rq2.js.map +1 -0
- package/dist/{presentation-types-8jLQHI4M.d.ts → presentation-types-B3VQH4Bz.d.ts} +19 -15
- package/dist/presentation-types-B3VQH4Bz.d.ts.map +1 -0
- package/dist/read.d.ts +6 -6
- package/dist/read.js +3 -3
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +11 -11
- package/dist/script.js.map +1 -1
- package/dist/{shapes-re0KyQk_.js → shapes-BcyFdZpp.js} +14 -10
- package/dist/shapes-BcyFdZpp.js.map +1 -0
- package/dist/{slide-Dx2ZeVZ6.d.ts → slide-BqPtyKmb.d.ts} +12 -7
- package/dist/slide-BqPtyKmb.d.ts.map +1 -0
- package/dist/{table-cell-margins-EVg0EwxT.js → table-cell-margins-PDshga8T.js} +4 -4
- package/dist/{table-cell-margins-EVg0EwxT.js.map → table-cell-margins-PDshga8T.js.map} +1 -1
- package/dist/{table-dom-BTDP3lEP.js → table-dom-CVbvUfgh.js} +3 -3
- package/dist/{table-dom-BTDP3lEP.js.map → table-dom-CVbvUfgh.js.map} +1 -1
- package/dist/{text-KnLOtEEu.js → text-BvFFMMFQ.js} +38 -36
- package/dist/{text-KnLOtEEu.js.map → text-BvFFMMFQ.js.map} +1 -1
- package/dist/{text-anchor-CrYXAfUu.js → text-anchor-BgLPbwbL.js} +2 -2
- package/dist/{text-anchor-CrYXAfUu.js.map → text-anchor-BgLPbwbL.js.map} +1 -1
- package/dist/{units-internal-XJlf-hOl.js → units-internal-DFcUYjh3.js} +11 -6
- package/dist/units-internal-DFcUYjh3.js.map +1 -0
- package/dist/{zip-C0leZZMj.d.ts → zip-CTll_dr0.d.ts} +2 -2
- package/dist/{zip-C0leZZMj.d.ts.map → zip-CTll_dr0.d.ts.map} +1 -1
- package/dist/{zip-CKd8ihcf.js → zip-CYZ0F6BV.js} +2 -2
- package/dist/{zip-CKd8ihcf.js.map → zip-CYZ0F6BV.js.map} +1 -1
- package/dist/zip.d.ts +2 -2
- package/dist/zip.js +2 -2
- package/dist/{zoom-cX9sllpH.js → zoom-BoNyOlPm.js} +66 -52
- package/dist/zoom-BoNyOlPm.js.map +1 -0
- package/package.json +39 -31
- package/skills/ts-pptx-upstream/SKILL.md +18 -18
- package/dist/html-dom-Iuog2wdK.js.map +0 -1
- package/dist/image-size-CvN2iCA4.js.map +0 -1
- package/dist/notes-Dh12JAbn.js.map +0 -1
- package/dist/pres-C6qgOFAa.d.ts.map +0 -1
- package/dist/presentation-DGYlAWhl.js.map +0 -1
- package/dist/presentation-types-8jLQHI4M.d.ts.map +0 -1
- package/dist/shapes-re0KyQk_.js.map +0 -1
- package/dist/slide-Dx2ZeVZ6.d.ts.map +0 -1
- package/dist/units-internal-XJlf-hOl.js.map +0 -1
- package/dist/zoom-cX9sllpH.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hn as imageFormatForExtension, mn as imageFormatForContentType } from "./image-size-DwDbakcl.js";
|
|
2
2
|
//#region src/media/content-type.ts
|
|
3
3
|
/**
|
|
4
4
|
* OPC content types for embedded media parts, keyed by file extension.
|
|
@@ -173,4 +173,4 @@ const VALIGN_BY_ANCHOR = Object.fromEntries(VALIGN_TABLE.map((row) => [row.ancho
|
|
|
173
173
|
//#endregion
|
|
174
174
|
export { avContentType as a, imageExtensionForSource as c, audioExtensionForSubtype as i, VALIGN_BY_ANCHOR as n, dataUriMediaType as o, assetFilenameExtension as r, imageContentType as s, TEXT_ANCHOR_BY_VALIGN as t };
|
|
175
175
|
|
|
176
|
-
//# sourceMappingURL=text-anchor-
|
|
176
|
+
//# sourceMappingURL=text-anchor-BgLPbwbL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-anchor-CrYXAfUu.js","names":[],"sources":["../src/media/content-type.ts","../src/ooxml/text-anchor.ts"],"sourcesContent":["/**\n * OPC content types for embedded media parts, keyed by file extension.\n *\n * Both mappings reproduce what PowerPoint itself authors rather than the IANA-preferred\n * spelling — a package that disagrees (e.g. `audio/mp3` for an `.mp3`) is the kind of thing\n * PowerPoint offers to repair.\n */\n\nimport { imageFormatForContentType, imageFormatForExtension } from './image-formats.js'\n\n/**\n * Map an image file extension to its OOXML content type, through the format registry in\n * `media/image-formats.ts`. An extension the registry does not carry falls through to\n * `image/<extn>`, which is right for any format whose content type is its extension.\n * Only the content type is derived here; the file extension (used for the media Target\n * filename) is left to the caller.\n * @param {string} extn - image file extension (e.g. `png`, `jpg`, `emf`)\n * @returns {string} OOXML content type (e.g. `image/png`, `image/x-emf`)\n */\nexport function imageContentType(extn: string): string {\n\treturn imageFormatForExtension(extn)?.contentType ?? 'image/' + (extn || '').toLowerCase()\n}\n\n/**\n * The media type an inline payload states in its header, lower-cased, or `null` when it states none.\n *\n * Takes a `data:` URI or the same header without its `data:` scheme (`image/png;base64,…`), the\n * two forms the definers accept. It is the one reading of that header: the patterns it replaces\n * each stopped short somewhere, `image\\/(\\w+);` at `-`, `.` and `+`, so `data:image/x-emf;…` named\n * no type and its EMF bytes were written into a `.png` part declared `image/png`.\n * @param data - a `data:` URI, a header-first base64 payload, or anything else\n * @returns the `type/subtype`, e.g. `image/x-emf`, or `null`\n */\nexport function dataUriMediaType(data: string): string | null {\n\tconst match = /^(?:data:)?([a-z]+\\/[\\w.+-]+)[;,]/i.exec(data || '')\n\treturn match?.[1]?.toLowerCase() ?? null\n}\n\n/**\n * Resolve the file extension an embedded image part should carry, from the caller's source.\n *\n * A `data:` URI states its mime type outright, so it wins over `path`: the bytes are the thing\n * being embedded, and a caller may supply them with no path at all (or with a path whose\n * extension disagrees with the payload). The extension chosen here names the media part *and*,\n * via {@link imageContentType}, decides the `<Default>` the package declares for it — so\n * getting it from a placeholder path is how a deck ends up declaring `image/png` over SVG\n * bytes, which is exactly the mismatch PowerPoint offers to \"repair\".\n *\n * A type the format registry carries names its part by the registry's extension (`image/x-emf` is\n * `emf`, `image/svg+xml` is `svg`). Any other type names it by its subtype, so `image/jpg` keeps\n * `jpg`. The result is always lower-cased, so a `data:image/PNG;` source names its part the same\n * way a `photo.PNG` path does.\n * @param {string} path - caller-supplied path/URL (may be empty); query and fragment are stripped\n * @param {string} data - caller-supplied `data:`/base64 payload (may be empty)\n * @returns {string} file extension, no dot (e.g. `png`, `jpeg`, `svg`)\n */\nexport function imageExtensionForSource(path: string, data: string): string {\n\t// NOTE: Split to address URLs with params (eg: `path/brent.jpg?someParam=true`)\n\tconst strPath = path || ''\n\tconst pathFile = strPath.slice(strPath.lastIndexOf('/') + 1).split('?')[0] || ''\n\tconst pathExtn = ((pathFile.split('.').pop() || 'png').split('#')[0] || 'png').toLowerCase()\n\n\tconst mime = dataUriMediaType(data)\n\tif (mime?.startsWith('image/')) return imageFormatForContentType(mime)?.ext ?? mime.slice('image/'.length)\n\treturn pathExtn\n}\n\n/**\n * Map an audio content type's subtype back to the file extension a media part should use.\n *\n * Needed because a caller supplying sound bytes as a `data:` URI states a *content type*\n * (`data:audio/x-wav;base64,…`), while the media part needs a *filename*. Taking the subtype\n * verbatim produces `audio1.x-wav` — legal, since the package would then declare a matching\n * `<Default Extension=\"x-wav\"/>`, but a file type that does not exist and that no other tool\n * recognises. `audio/x-wav` in particular is not an edge case: it is exactly what PowerPoint\n * authors for an embedded transition sound, so it arrives on any deck read back in.\n *\n * Only the spellings that are *not* already an extension are listed; anything else (`ogg`,\n * `flac`, `aac`, …) is its own extension and falls through. Read against {@link avContentType},\n * which maps the same pairs in the other direction.\n */\nexport function audioExtensionForSubtype(subtype: string): string {\n\tswitch ((subtype || '').toLowerCase()) {\n\t\tcase 'x-wav':\n\t\tcase 'wave':\n\t\tcase 'vnd.wave':\n\t\t\treturn 'wav'\n\t\tcase 'mpeg':\n\t\t\treturn 'mp3'\n\t\tcase 'x-ms-wma':\n\t\t\treturn 'wma'\n\t\tcase 'mp4':\n\t\t\treturn 'm4a'\n\t\tdefault:\n\t\t\treturn (subtype || '').toLowerCase()\n\t}\n}\n\n/**\n * Resolve the OPC content type for an embedded audio/video part by file extension,\n * matching what PowerPoint authors (e.g. `mp3` → `audio/mpeg`, not `audio/mp3`).\n * The `mtype` disambiguates extensions Office maps differently per kind and seeds\n * the `mtype/extn` fallback for anything unlisted.\n * @param {string} extn - media file extension (no dot), case-insensitive\n * @param {'audio' | 'video'} mtype - whether the item is audio or video\n */\nexport function avContentType(extn: string, mtype: 'audio' | 'video'): string {\n\tswitch ((extn || '').toLowerCase()) {\n\t\t// video\n\t\tcase 'mp4':\n\t\t\treturn mtype === 'audio' ? 'audio/mp4' : 'video/mp4'\n\t\tcase 'm4v':\n\t\t\treturn 'video/mp4'\n\t\tcase 'mov':\n\t\t\treturn 'video/quicktime'\n\t\tcase 'avi':\n\t\t\treturn 'video/avi'\n\t\tcase 'wmv':\n\t\t\treturn 'video/x-ms-wmv'\n\t\tcase 'mpg':\n\t\tcase 'mpeg':\n\t\t\treturn mtype === 'audio' ? 'audio/mpeg' : 'video/mpeg'\n\t\tcase 'ogv':\n\t\t\treturn 'video/ogg'\n\t\tcase 'webm':\n\t\t\treturn 'video/webm'\n\t\t// audio\n\t\tcase 'mp3':\n\t\t\treturn 'audio/mpeg'\n\t\tcase 'm4a':\n\t\t\treturn 'audio/mp4'\n\t\tcase 'wav':\n\t\t\treturn 'audio/x-wav' // PowerPoint authors the x- form (e.g. embedded transition sounds)\n\t\tcase 'wma':\n\t\t\treturn 'audio/x-ms-wma'\n\t\tcase 'aac':\n\t\t\treturn 'audio/aac'\n\t\tcase 'oga':\n\t\tcase 'ogg':\n\t\t\treturn 'audio/ogg'\n\t\tcase 'flac':\n\t\t\treturn 'audio/flac'\n\t\tdefault:\n\t\t\treturn mtype + '/' + (extn || '').toLowerCase()\n\t}\n}\n\n/**\n * The extension an emitted *asset filename* should carry for a media content type, or `null`\n * when nothing here names one and the caller should fall back to the source part's own suffix.\n *\n * This is the on-disk spelling, not the media part's: `image/jpeg` is `jpg` and `image/tiff` is\n * `tif` here, because an asset directory is read by people and opened by desktop viewers. See the\n * `filenameExt` column in `media/image-formats.ts`. Audio goes through {@link audioExtensionForSubtype}, which is\n * already the one table for that direction.\n */\nexport function assetFilenameExtension(contentType: string): string | null {\n\tconst image = imageFormatForContentType(contentType)\n\tif (image) return image.filenameExt\n\tconst ct = (contentType || '').toLowerCase()\n\treturn ct.startsWith('audio/') ? audioExtensionForSubtype(ct.slice('audio/'.length)) : null\n}\n","/**\n * `a:bodyPr/@anchor` and `a:tcPr/@anchor`, and the write API's `valign` on the other side of it.\n *\n * Two tables stated the same correspondence in opposite directions and could not see each other:\n * the emitters' spelling table in `gen/drawingml/text-body.ts`, and its hand-written inverse in\n * `script/from-read/values.ts`, which maps a read deck's anchor back to the `valign` a generated\n * script writes. `script/` cannot import `gen/` — it has no such import anywhere, deliberately —\n * so the inverse could not be derived where it stood, and a token added to one table would have\n * meant a script that reads an anchor it cannot write back.\n *\n * The correspondence itself is a fact about the format, so it lives here, as one table with both\n * directions derived from it.\n *\n * This module keeps `ooxml/`'s no-runtime-imports property: {@link TEXT_ANCHORS} is the schema's\n * own list from a module with none either, and the {@link TextAnchor} reference is type-only, so\n * it is erased. That reference is still a real check — it is what ties the enum the write API\n * exposes to the tokens named here.\n */\n\nimport type { TextAnchor } from '../enums.js'\nimport { TEXT_ANCHORS } from './st-enums.js'\n\n/**\n * The `ST_TextAnchoringType` tokens this library writes, checked against both the schema's list\n * and the public {@link TextAnchor} enum.\n *\n * `Extract` is that check twice over: a token here that is not in `ST_TextAnchoringType`, or not\n * in the enum, is dropped from the type and the table below stops compiling. Compile-time on\n * purpose — every value in the table is a literal, so a runtime check could never fail, and a\n * check that cannot fail is worse than none.\n *\n * The library writes three of the schema's five: `just` and `dist` are anchoring modes no\n * option surfaces.\n */\nexport type TextAnchorToken = Extract<`${TextAnchor}`, (typeof TEXT_ANCHORS)[number]>\n\n/**\n * Every `valign` the write API accepts, the anchor token it means, and the other spellings the\n * definers between them have always taken.\n *\n * The three definers read `valign` three ways — `startsWith('b'|'m'|'t')`, a chain of\n * `.replace('top','t')…` that let any other string through *verbatim* into `anchor=`, and a\n * longer chain that also took `btm` and `center`. This table is the union of what they named;\n * anything else is a warning and an omitted attribute rather than an invalid one.\n *\n * `valign` leads each row because it is the direction with a preferred answer: several spellings\n * mean one anchor, and only one of them is what a generated script should write back.\n */\nconst VALIGN_TABLE = [\n\t{ valign: 'top', anchor: 't', aliases: ['t'] },\n\t{ valign: 'middle', anchor: 'ctr', aliases: ['c', 'ctr', 'center', 'm'] },\n\t{ valign: 'bottom', anchor: 'b', aliases: ['b', 'btm'] },\n] as const satisfies ReadonlyArray<{ valign: string; anchor: TextAnchorToken; aliases: readonly string[] }>\n\n/** Every spelling of `valign` the definers accept, mapped to the one anchor token it means. */\nexport const TEXT_ANCHOR_BY_VALIGN: Readonly<Record<string, TextAnchorToken>> = Object.fromEntries(\n\tVALIGN_TABLE.flatMap((row) => [row.valign, ...row.aliases].map((spelling) => [spelling, row.anchor]))\n)\n\n/**\n * An anchor token back to the `valign` a generated script writes — the preferred spelling of the\n * row, never one of its aliases.\n */\nexport const VALIGN_BY_ANCHOR: Readonly<Record<string, string>> = Object.fromEntries(\n\tVALIGN_TABLE.map((row) => [row.anchor, row.valign])\n)\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,SAAgB,iBAAiB,MAAsB;CACtD,OAAO,wBAAwB,IAAI,CAAC,EAAE,eAAe,YAAY,QAAQ,GAAA,CAAI,YAAY;AAC1F;;;;;;;;;;;AAYA,SAAgB,iBAAiB,MAA6B;CAE7D,OADc,qCAAqC,KAAK,QAAQ,EACrD,CAAC,GAAG,EAAE,EAAE,YAAY,KAAK;AACrC;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,wBAAwB,MAAc,MAAsB;CAE3E,MAAM,UAAU,QAAQ;CAExB,MAAM,cADW,QAAQ,MAAM,QAAQ,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,GAAA,CAClD,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,MAAA,CAAO,MAAM,GAAG,CAAC,CAAC,MAAM,MAAA,CAAO,YAAY;CAE3F,MAAM,OAAO,iBAAiB,IAAI;CAClC,IAAI,MAAM,WAAW,QAAQ,GAAG,OAAO,0BAA0B,IAAI,CAAC,EAAE,OAAO,KAAK,MAAM,CAAe;CACzG,OAAO;AACR;;;;;;;;;;;;;;;AAgBA,SAAgB,yBAAyB,SAAyB;CACjE,SAAS,WAAW,GAAA,CAAI,YAAY,GAApC;EACC,KAAK;EACL,KAAK;EACL,KAAK,YACJ,OAAO;EACR,KAAK,QACJ,OAAO;EACR,KAAK,YACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,SACC,QAAQ,WAAW,GAAA,CAAI,YAAY;CACrC;AACD;;;;;;;;;AAUA,SAAgB,cAAc,MAAc,OAAkC;CAC7E,SAAS,QAAQ,GAAA,CAAI,YAAY,GAAjC;EAEC,KAAK,OACJ,OAAO,UAAU,UAAU,cAAc;EAC1C,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK;EACL,KAAK,QACJ,OAAO,UAAU,UAAU,eAAe;EAC3C,KAAK,OACJ,OAAO;EACR,KAAK,QACJ,OAAO;EAER,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK;EACL,KAAK,OACJ,OAAO;EACR,KAAK,QACJ,OAAO;EACR,SACC,OAAO,QAAQ,OAAO,QAAQ,GAAA,CAAI,YAAY;CAChD;AACD;;;;;;;;;;AAWA,SAAgB,uBAAuB,aAAoC;CAC1E,MAAM,QAAQ,0BAA0B,WAAW;CACnD,IAAI,OAAO,OAAO,MAAM;CACxB,MAAM,MAAM,eAAe,GAAA,CAAI,YAAY;CAC3C,OAAO,GAAG,WAAW,QAAQ,IAAI,yBAAyB,GAAG,MAAM,CAAe,CAAC,IAAI;AACxF;;;;;;;;;;;;;;;ACjHA,MAAM,eAAe;CACpB;EAAE,QAAQ;EAAO,QAAQ;EAAK,SAAS,CAAC,GAAG;CAAE;CAC7C;EAAE,QAAQ;EAAU,QAAQ;EAAO,SAAS;GAAC;GAAK;GAAO;GAAU;EAAG;CAAE;CACxE;EAAE,QAAQ;EAAU,QAAQ;EAAK,SAAS,CAAC,KAAK,KAAK;CAAE;AACxD;;AAGA,MAAa,wBAAmE,OAAO,YACtF,aAAa,SAAS,QAAQ,CAAC,IAAI,QAAQ,GAAG,IAAI,OAAO,CAAC,CAAC,KAAK,aAAa,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC,CACrG;;;;;AAMA,MAAa,mBAAqD,OAAO,YACxE,aAAa,KAAK,QAAQ,CAAC,IAAI,QAAQ,IAAI,MAAM,CAAC,CACnD"}
|
|
1
|
+
{"version":3,"file":"text-anchor-BgLPbwbL.js","names":[],"sources":["../src/media/content-type.ts","../src/ooxml/text-anchor.ts"],"sourcesContent":["/**\n * OPC content types for embedded media parts, keyed by file extension.\n *\n * Both mappings reproduce what PowerPoint itself authors rather than the IANA-preferred\n * spelling — a package that disagrees (e.g. `audio/mp3` for an `.mp3`) is the kind of thing\n * PowerPoint offers to repair.\n */\n\nimport { imageFormatForContentType, imageFormatForExtension } from './image-formats.js'\n\n/**\n * Map an image file extension to its OOXML content type, through the format registry in\n * `media/image-formats.ts`. An extension the registry does not carry falls through to\n * `image/<extn>`, which is right for any format whose content type is its extension.\n * Only the content type is derived here; the file extension (used for the media Target\n * filename) is left to the caller.\n * @param {string} extn - image file extension (e.g. `png`, `jpg`, `emf`)\n * @returns {string} OOXML content type (e.g. `image/png`, `image/x-emf`)\n */\nexport function imageContentType(extn: string): string {\n\treturn imageFormatForExtension(extn)?.contentType ?? 'image/' + (extn || '').toLowerCase()\n}\n\n/**\n * The media type an inline payload states in its header, lower-cased, or `null` when it states none.\n *\n * Takes a `data:` URI or the same header without its `data:` scheme (`image/png;base64,…`), the\n * two forms the definers accept. It is the one reading of that header: the patterns it replaces\n * each stopped short somewhere, `image\\/(\\w+);` at `-`, `.` and `+`, so `data:image/x-emf;…` named\n * no type and its EMF bytes were written into a `.png` part declared `image/png`.\n * @param data - a `data:` URI, a header-first base64 payload, or anything else\n * @returns the `type/subtype`, e.g. `image/x-emf`, or `null`\n */\nexport function dataUriMediaType(data: string): string | null {\n\tconst match = /^(?:data:)?([a-z]+\\/[\\w.+-]+)[;,]/i.exec(data || '')\n\treturn match?.[1]?.toLowerCase() ?? null\n}\n\n/**\n * Resolve the file extension an embedded image part should carry, from the caller's source.\n *\n * A `data:` URI states its mime type outright, so it wins over `path`: the bytes are the thing\n * being embedded, and a caller may supply them with no path at all (or with a path whose\n * extension disagrees with the payload). The extension chosen here names the media part *and*,\n * via {@link imageContentType}, decides the `<Default>` the package declares for it — so\n * getting it from a placeholder path is how a deck ends up declaring `image/png` over SVG\n * bytes, which is exactly the mismatch PowerPoint offers to \"repair\".\n *\n * A type the format registry carries names its part by the registry's extension (`image/x-emf` is\n * `emf`, `image/svg+xml` is `svg`). Any other type names it by its subtype, so `image/jpg` keeps\n * `jpg`. The result is always lower-cased, so a `data:image/PNG;` source names its part the same\n * way a `photo.PNG` path does.\n * @param {string} path - caller-supplied path/URL (may be empty); query and fragment are stripped\n * @param {string} data - caller-supplied `data:`/base64 payload (may be empty)\n * @returns {string} file extension, no dot (e.g. `png`, `jpeg`, `svg`)\n */\nexport function imageExtensionForSource(path: string, data: string): string {\n\t// NOTE: Split to address URLs with params (eg: `path/brent.jpg?someParam=true`)\n\tconst strPath = path || ''\n\tconst pathFile = strPath.slice(strPath.lastIndexOf('/') + 1).split('?')[0] || ''\n\tconst pathExtn = ((pathFile.split('.').pop() || 'png').split('#')[0] || 'png').toLowerCase()\n\n\tconst mime = dataUriMediaType(data)\n\tif (mime?.startsWith('image/')) return imageFormatForContentType(mime)?.ext ?? mime.slice('image/'.length)\n\treturn pathExtn\n}\n\n/**\n * Map an audio content type's subtype back to the file extension a media part should use.\n *\n * Needed because a caller supplying sound bytes as a `data:` URI states a *content type*\n * (`data:audio/x-wav;base64,…`), while the media part needs a *filename*. Taking the subtype\n * verbatim produces `audio1.x-wav` — legal, since the package would then declare a matching\n * `<Default Extension=\"x-wav\"/>`, but a file type that does not exist and that no other tool\n * recognises. `audio/x-wav` in particular is not an edge case: it is exactly what PowerPoint\n * authors for an embedded transition sound, so it arrives on any deck read back in.\n *\n * Only the spellings that are *not* already an extension are listed; anything else (`ogg`,\n * `flac`, `aac`, …) is its own extension and falls through. Read against {@link avContentType},\n * which maps the same pairs in the other direction.\n */\nexport function audioExtensionForSubtype(subtype: string): string {\n\tswitch ((subtype || '').toLowerCase()) {\n\t\tcase 'x-wav':\n\t\tcase 'wave':\n\t\tcase 'vnd.wave':\n\t\t\treturn 'wav'\n\t\tcase 'mpeg':\n\t\t\treturn 'mp3'\n\t\tcase 'x-ms-wma':\n\t\t\treturn 'wma'\n\t\tcase 'mp4':\n\t\t\treturn 'm4a'\n\t\tdefault:\n\t\t\treturn (subtype || '').toLowerCase()\n\t}\n}\n\n/**\n * Resolve the OPC content type for an embedded audio/video part by file extension,\n * matching what PowerPoint authors (e.g. `mp3` → `audio/mpeg`, not `audio/mp3`).\n * The `mtype` disambiguates extensions Office maps differently per kind and seeds\n * the `mtype/extn` fallback for anything unlisted.\n * @param {string} extn - media file extension (no dot), case-insensitive\n * @param {'audio' | 'video'} mtype - whether the item is audio or video\n */\nexport function avContentType(extn: string, mtype: 'audio' | 'video'): string {\n\tswitch ((extn || '').toLowerCase()) {\n\t\t// video\n\t\tcase 'mp4':\n\t\t\treturn mtype === 'audio' ? 'audio/mp4' : 'video/mp4'\n\t\tcase 'm4v':\n\t\t\treturn 'video/mp4'\n\t\tcase 'mov':\n\t\t\treturn 'video/quicktime'\n\t\tcase 'avi':\n\t\t\treturn 'video/avi'\n\t\tcase 'wmv':\n\t\t\treturn 'video/x-ms-wmv'\n\t\tcase 'mpg':\n\t\tcase 'mpeg':\n\t\t\treturn mtype === 'audio' ? 'audio/mpeg' : 'video/mpeg'\n\t\tcase 'ogv':\n\t\t\treturn 'video/ogg'\n\t\tcase 'webm':\n\t\t\treturn 'video/webm'\n\t\t// audio\n\t\tcase 'mp3':\n\t\t\treturn 'audio/mpeg'\n\t\tcase 'm4a':\n\t\t\treturn 'audio/mp4'\n\t\tcase 'wav':\n\t\t\treturn 'audio/x-wav' // PowerPoint authors the x- form (e.g. embedded transition sounds)\n\t\tcase 'wma':\n\t\t\treturn 'audio/x-ms-wma'\n\t\tcase 'aac':\n\t\t\treturn 'audio/aac'\n\t\tcase 'oga':\n\t\tcase 'ogg':\n\t\t\treturn 'audio/ogg'\n\t\tcase 'flac':\n\t\t\treturn 'audio/flac'\n\t\tdefault:\n\t\t\treturn mtype + '/' + (extn || '').toLowerCase()\n\t}\n}\n\n/**\n * The extension an emitted *asset filename* should carry for a media content type, or `null`\n * when nothing here names one and the caller should fall back to the source part's own suffix.\n *\n * This is the on-disk spelling, not the media part's: `image/jpeg` is `jpg` and `image/tiff` is\n * `tif` here, because an asset directory is read by people and opened by desktop viewers. See the\n * `filenameExt` column in `media/image-formats.ts`. Audio goes through {@link audioExtensionForSubtype}, which is\n * already the one table for that direction.\n */\nexport function assetFilenameExtension(contentType: string): string | null {\n\tconst image = imageFormatForContentType(contentType)\n\tif (image) return image.filenameExt\n\tconst ct = (contentType || '').toLowerCase()\n\treturn ct.startsWith('audio/') ? audioExtensionForSubtype(ct.slice('audio/'.length)) : null\n}\n","/**\n * `a:bodyPr/@anchor` and `a:tcPr/@anchor`, and the write API's `valign` on the other side of it.\n *\n * Two tables stated the same correspondence in opposite directions and could not see each other:\n * the emitters' spelling table in `gen/drawingml/text-body.ts`, and its hand-written inverse in\n * `script/from-read/values.ts`, which maps a read deck's anchor back to the `valign` a generated\n * script writes. `script/` cannot import `gen/` — it has no such import anywhere, deliberately —\n * so the inverse could not be derived where it stood, and a token added to one table would have\n * meant a script that reads an anchor it cannot write back.\n *\n * The correspondence itself is a fact about the format, so it lives here, as one table with both\n * directions derived from it.\n *\n * This module keeps `ooxml/`'s no-runtime-imports property: {@link TEXT_ANCHORS} is the schema's\n * own list from a module with none either, and the {@link TextAnchor} reference is type-only, so\n * it is erased. That reference is still a real check — it is what ties the enum the write API\n * exposes to the tokens named here.\n */\n\nimport type { TextAnchor } from '../enums.js'\nimport { TEXT_ANCHORS } from './st-enums.js'\n\n/**\n * The `ST_TextAnchoringType` tokens this library writes, checked against both the schema's list\n * and the public {@link TextAnchor} enum.\n *\n * `Extract` is that check twice over: a token here that is not in `ST_TextAnchoringType`, or not\n * in the enum, is dropped from the type and the table below stops compiling. Compile-time on\n * purpose — every value in the table is a literal, so a runtime check could never fail, and a\n * check that cannot fail is worse than none.\n *\n * The library writes three of the schema's five: `just` and `dist` are anchoring modes no\n * option surfaces.\n */\nexport type TextAnchorToken = Extract<`${TextAnchor}`, (typeof TEXT_ANCHORS)[number]>\n\n/**\n * Every `valign` the write API accepts, the anchor token it means, and the other spellings the\n * definers between them have always taken.\n *\n * The three definers read `valign` three ways — `startsWith('b'|'m'|'t')`, a chain of\n * `.replace('top','t')…` that let any other string through *verbatim* into `anchor=`, and a\n * longer chain that also took `btm` and `center`. This table is the union of what they named;\n * anything else is a warning and an omitted attribute rather than an invalid one.\n *\n * `valign` leads each row because it is the direction with a preferred answer: several spellings\n * mean one anchor, and only one of them is what a generated script should write back.\n */\nconst VALIGN_TABLE = [\n\t{ valign: 'top', anchor: 't', aliases: ['t'] },\n\t{ valign: 'middle', anchor: 'ctr', aliases: ['c', 'ctr', 'center', 'm'] },\n\t{ valign: 'bottom', anchor: 'b', aliases: ['b', 'btm'] },\n] as const satisfies ReadonlyArray<{ valign: string; anchor: TextAnchorToken; aliases: readonly string[] }>\n\n/** Every spelling of `valign` the definers accept, mapped to the one anchor token it means. */\nexport const TEXT_ANCHOR_BY_VALIGN: Readonly<Record<string, TextAnchorToken>> = Object.fromEntries(\n\tVALIGN_TABLE.flatMap((row) => [row.valign, ...row.aliases].map((spelling) => [spelling, row.anchor]))\n)\n\n/**\n * An anchor token back to the `valign` a generated script writes — the preferred spelling of the\n * row, never one of its aliases.\n */\nexport const VALIGN_BY_ANCHOR: Readonly<Record<string, string>> = Object.fromEntries(\n\tVALIGN_TABLE.map((row) => [row.anchor, row.valign])\n)\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,SAAgB,iBAAiB,MAAsB;CACtD,OAAO,wBAAwB,IAAI,CAAC,EAAE,eAAe,YAAY,QAAQ,GAAA,CAAI,YAAY;AAC1F;;;;;;;;;;;AAYA,SAAgB,iBAAiB,MAA6B;CAE7D,OADc,qCAAqC,KAAK,QAAQ,EACrD,CAAC,GAAG,EAAE,EAAE,YAAY,KAAK;AACrC;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,wBAAwB,MAAc,MAAsB;CAE3E,MAAM,UAAU,QAAQ;CAExB,MAAM,cADW,QAAQ,MAAM,QAAQ,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,GAAA,CAClD,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,MAAA,CAAO,MAAM,GAAG,CAAC,CAAC,MAAM,MAAA,CAAO,YAAY;CAE3F,MAAM,OAAO,iBAAiB,IAAI;CAClC,IAAI,MAAM,WAAW,QAAQ,GAAG,OAAO,0BAA0B,IAAI,CAAC,EAAE,OAAO,KAAK,MAAM,CAAe;CACzG,OAAO;AACR;;;;;;;;;;;;;;;AAgBA,SAAgB,yBAAyB,SAAyB;CACjE,SAAS,WAAW,GAAA,CAAI,YAAY,GAApC;EACC,KAAK;EACL,KAAK;EACL,KAAK,YACJ,OAAO;EACR,KAAK,QACJ,OAAO;EACR,KAAK,YACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,SACC,QAAQ,WAAW,GAAA,CAAI,YAAY;CACrC;AACD;;;;;;;;;AAUA,SAAgB,cAAc,MAAc,OAAkC;CAC7E,SAAS,QAAQ,GAAA,CAAI,YAAY,GAAjC;EAEC,KAAK,OACJ,OAAO,UAAU,UAAU,cAAc;EAC1C,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK;EACL,KAAK,QACJ,OAAO,UAAU,UAAU,eAAe;EAC3C,KAAK,OACJ,OAAO;EACR,KAAK,QACJ,OAAO;EAER,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK;EACL,KAAK,OACJ,OAAO;EACR,KAAK,QACJ,OAAO;EACR,SACC,OAAO,QAAQ,OAAO,QAAQ,GAAA,CAAI,YAAY;CAChD;AACD;;;;;;;;;;AAWA,SAAgB,uBAAuB,aAAoC;CAC1E,MAAM,QAAQ,0BAA0B,WAAW;CACnD,IAAI,OAAO,OAAO,MAAM;CACxB,MAAM,MAAM,eAAe,GAAA,CAAI,YAAY;CAC3C,OAAO,GAAG,WAAW,QAAQ,IAAI,yBAAyB,GAAG,MAAM,CAAe,CAAC,IAAI;AACxF;;;;;;;;;;;;;;;ACjHA,MAAM,eAAe;CACpB;EAAE,QAAQ;EAAO,QAAQ;EAAK,SAAS,CAAC,GAAG;CAAE;CAC7C;EAAE,QAAQ;EAAU,QAAQ;EAAO,SAAS;GAAC;GAAK;GAAO;GAAU;EAAG;CAAE;CACxE;EAAE,QAAQ;EAAU,QAAQ;EAAK,SAAS,CAAC,KAAK,KAAK;CAAE;AACxD;;AAGA,MAAa,wBAAmE,OAAO,YACtF,aAAa,SAAS,QAAQ,CAAC,IAAI,QAAQ,GAAG,IAAI,OAAO,CAAC,CAAC,KAAK,aAAa,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC,CACrG;;;;;AAMA,MAAa,mBAAqD,OAAO,YACxE,aAAa,KAAK,QAAQ,CAAC,IAAI,QAAQ,IAAI,MAAM,CAAC,CACnD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as warn, n as InvalidOptionError, u as warnOnce } from "./errors-
|
|
2
|
-
import { A as inchesToEmu, E as coordToEmu, F as EMU_PER_INCH, I as EMU_PER_POINT, S as MAX_COORDINATE_EMU, b as FIXED_PCT_PER_PERCENT, t as TABLE_CELL_MARGIN_DEFAULTS_EMU, v as ANGLE_UNITS_PER_DEGREE, w as PERCENT_SCALE } from "./table-cell-margins-
|
|
1
|
+
import { l as warn, n as InvalidOptionError, u as warnOnce } from "./errors-Da2nXCJm.js";
|
|
2
|
+
import { A as inchesToEmu, E as coordToEmu, F as EMU_PER_INCH, I as EMU_PER_POINT, S as MAX_COORDINATE_EMU, b as FIXED_PCT_PER_PERCENT, t as TABLE_CELL_MARGIN_DEFAULTS_EMU, v as ANGLE_UNITS_PER_DEGREE, w as PERCENT_SCALE } from "./table-cell-margins-PDshga8T.js";
|
|
3
3
|
//#region src/ooxml/ids.ts
|
|
4
4
|
/** `ST_SlideId` maximum, inclusive. The schema's `maxExclusive` is 2147483648. */
|
|
5
5
|
const MAX_SLIDE_ID = 2147483647;
|
|
@@ -8,6 +8,11 @@ const MAX_SLIDE_ID = 2147483647;
|
|
|
8
8
|
* from one id space that must be unique across the whole presentation.
|
|
9
9
|
*/
|
|
10
10
|
const MIN_SLIDE_MASTER_ID = 2147483648;
|
|
11
|
+
/**
|
|
12
|
+
* `ST_Guid`: upper-case hex in braces, the schema's own pattern. `a:tableStyleId` is one; a
|
|
13
|
+
* lower-case or unbraced GUID fails it.
|
|
14
|
+
*/
|
|
15
|
+
const ST_GUID = /^\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}$/;
|
|
11
16
|
//#endregion
|
|
12
17
|
//#region src/constants-internal.ts
|
|
13
18
|
const LAYOUT_IDX_SERIES_BASE = 2147483649;
|
|
@@ -116,8 +121,8 @@ const LEVEL_MARGINS_EMU = Array.from({ length: 9 }, (_, i) => i * (EMU_PER_INCH
|
|
|
116
121
|
* The fourth computes it per level — a configured master's title can be centred or right —
|
|
117
122
|
* and a spread that carried `algn` would silently overwrite that: a later key in an object
|
|
118
123
|
* literal replaces the value without moving the key, so the attribute order would still look
|
|
119
|
-
* right while the alignment was wrong. No
|
|
120
|
-
* `byte-identity` cannot see that path; `master-text-styles.test.
|
|
124
|
+
* right while the alignment was wrong. No gate deck configures a master text style, so
|
|
125
|
+
* `byte-identity` cannot see that path; `master-text-styles.test.ts` pins it instead.
|
|
121
126
|
*/
|
|
122
127
|
const LEVEL_PPR_TAIL = {
|
|
123
128
|
defTabSz: EMU_PER_INCH,
|
|
@@ -644,6 +649,6 @@ function convertArcAngle(d, attr) {
|
|
|
644
649
|
return convertAngleUnits(d, `Arc ${attr}`, "geometry/arc-angle-non-finite");
|
|
645
650
|
}
|
|
646
651
|
//#endregion
|
|
647
|
-
export { DEF_CELL_BORDER as A, DEF_TEXT_SHADOW as B, usableTableWidthEmu as C, AXIS_ID_VALUE_PRIMARY as D, AXIS_ID_SERIES_PRIMARY as E, DEF_PRES_LAYOUT_NAME as F, MAX_FONT_SIZE_PT as G, LETTERS as H, DEF_SHAPE_LINE_COLOR as I, SLDNUM_PLACEHOLDER_TEXT as J, PIECHART_COLORS as K, DEF_SHAPE_SHADOW as L, DEF_CHART_GRIDLINE as M, DEF_FONT_COLOR as N, AXIS_ID_VALUE_SECONDARY as O, DEF_PRES_LAYOUT as P, DEF_SLIDE_MARGIN_IN as R, transparencyToAlpha as S, AXIS_ID_CATEGORY_SECONDARY as T, LEVEL_MARGINS_EMU as U, LAYOUT_IDX_SERIES_BASE as V, LEVEL_PPR_TAIL as W, MIN_SLIDE_MASTER_ID as X, MAX_SLIDE_ID as Y, resolveCellMarginsInches as _, convertRotationDegrees as a, resolveTableColWidthsEmu as b, inch2Emu as c, marginToEmu as d, opacityToAlpha as f, ptsToEmuLenient as g, positiveCoordinateEmu as h, convertArcAngle as i, DEF_CHART_BORDER as j, BARCHART_COLORS as k, lineWidthToEmu as l, pinnedRowHeightInches as m, clampRangedInput as n, fractionToFixedPercent as o, percentToFixedPercent as p, SLDNUMFLDID as q, convertAngleUnits as r, getSmartParseNumber as s, autoPageLineHeightEmu as t, mapStated as u, resolveInsetsEmu as v, AXIS_ID_CATEGORY_PRIMARY as w, resolveTableRowHeightEmu as x, resolveSlideMarginsInches as y, DEF_TEXT_GLOW as z };
|
|
652
|
+
export { DEF_CELL_BORDER as A, DEF_TEXT_SHADOW as B, usableTableWidthEmu as C, AXIS_ID_VALUE_PRIMARY as D, AXIS_ID_SERIES_PRIMARY as E, DEF_PRES_LAYOUT_NAME as F, MAX_FONT_SIZE_PT as G, LETTERS as H, DEF_SHAPE_LINE_COLOR as I, SLDNUM_PLACEHOLDER_TEXT as J, PIECHART_COLORS as K, DEF_SHAPE_SHADOW as L, DEF_CHART_GRIDLINE as M, DEF_FONT_COLOR as N, AXIS_ID_VALUE_SECONDARY as O, DEF_PRES_LAYOUT as P, DEF_SLIDE_MARGIN_IN as R, transparencyToAlpha as S, AXIS_ID_CATEGORY_SECONDARY as T, LEVEL_MARGINS_EMU as U, LAYOUT_IDX_SERIES_BASE as V, LEVEL_PPR_TAIL as W, MIN_SLIDE_MASTER_ID as X, MAX_SLIDE_ID as Y, ST_GUID as Z, resolveCellMarginsInches as _, convertRotationDegrees as a, resolveTableColWidthsEmu as b, inch2Emu as c, marginToEmu as d, opacityToAlpha as f, ptsToEmuLenient as g, positiveCoordinateEmu as h, convertArcAngle as i, DEF_CHART_BORDER as j, BARCHART_COLORS as k, lineWidthToEmu as l, pinnedRowHeightInches as m, clampRangedInput as n, fractionToFixedPercent as o, percentToFixedPercent as p, SLDNUMFLDID as q, convertAngleUnits as r, getSmartParseNumber as s, autoPageLineHeightEmu as t, mapStated as u, resolveInsetsEmu as v, AXIS_ID_CATEGORY_PRIMARY as w, resolveTableRowHeightEmu as x, resolveSlideMarginsInches as y, DEF_TEXT_GLOW as z };
|
|
648
653
|
|
|
649
|
-
//# sourceMappingURL=units-internal-
|
|
654
|
+
//# sourceMappingURL=units-internal-DFcUYjh3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"units-internal-DFcUYjh3.js","names":[],"sources":["../src/ooxml/ids.ts","../src/constants-internal.ts","../src/units-internal.ts"],"sourcesContent":["/**\n * The bounds of the three id spaces `presentation.xml` numbers its parts in, and the shape of a\n * GUID-valued id.\n *\n * The write path, the read model's slide and master registries, and the Slide Zoom definer each\n * spelled these as literals or as a private constant of their own. They are facts about the\n * format, so they live here once.\n *\n * Imports nothing, like the rest of `ooxml/`.\n */\n\n/** `ST_SlideId` minimum: `p:sldId/@id` starts at 256. */\nexport const MIN_SLIDE_ID = 256\n\n/** `ST_SlideId` maximum, inclusive. The schema's `maxExclusive` is 2147483648. */\nexport const MAX_SLIDE_ID = 2147483647\n\n/**\n * `ST_SlideMasterId` minimum (0x80000000). `ST_SlideLayoutId` has the same floor, and the two draw\n * from one id space that must be unique across the whole presentation.\n */\nexport const MIN_SLIDE_MASTER_ID = 2147483648\n\n/** `ST_SlideLayoutId` minimum (0x80000000): the same floor as {@link MIN_SLIDE_MASTER_ID}. */\nexport const MIN_SLIDE_LAYOUT_ID = 2147483648\n\n/**\n * `ST_Guid`: upper-case hex in braces, the schema's own pattern. `a:tableStyleId` is one; a\n * lower-case or unbraced GUID fails it.\n */\nexport const ST_GUID = /^\\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\\}$/\n","/**\n * Generator-internal constants — the non-published half of the enums module.\n *\n * `enums.ts` holds the genuinely public surface (the `ChartType`/`ShapeType`/\n * `SchemeColor`/`AlignH`… enums, the shape-preset sets, and the `*_NAME` unions) and is\n * `export *`-ed by every entrypoint. This module holds the constants only the generators\n * need — default styling, fixed axis/field ids, colour palettes, layout bases, and the\n * base64 placeholder images — none of which are part of the public API. Splitting them out\n * keeps `export *` from leaking them onto the package surface, mirroring the\n * `units-internal.ts` / `types/internal.ts` split. Nothing here is exported from an entrypoint.\n */\n\nimport type { BorderProps, OptsChartGridLine } from './types/index.js'\nimport type { ShadowPropsInternal } from './types/internal.js'\nimport { EMU_PER_INCH, EMU_PER_POINT } from './units.js'\nimport { MIN_SLIDE_LAYOUT_ID } from './ooxml/ids.js'\nimport { TABLE_CELL_MARGIN_DEFAULTS_EMU } from './ooxml/table-cell-margins.js'\n\n// CONST\nexport const CRLF = '\\r\\n' // AKA: Chr(13) & Chr(10)\n// Base for `<p:sldLayoutId id>` (layout N gets BASE + N). One past the ST_SlideLayoutId floor,\n// where PowerPoint conventionally starts layout IDs: the floor itself is the master's id, and the\n// two share one id space. See `makeXmlMaster` in `gen/slide/master.ts`.\nexport const LAYOUT_IDX_SERIES_BASE = MIN_SLIDE_LAYOUT_ID + 1\nexport const LINEH_MODIFIER = 1.67 // AKA: Golden Ratio Typography\n\nexport const DEF_BULLET_MARGIN = 27\n// `satisfies` rather than an annotation: callers read `.type`/`.color`/`.width` off these to *fill\n// in* a side that stated none, so the constant has to be known to state them itself. Annotated as\n// `BorderProps` all three are `T | undefined`, and the fallback is not assignable to the field it\n// is the fallback for.\nexport const DEF_CELL_BORDER = { type: 'solid', color: '666666', width: 1 } as const satisfies BorderProps\n// A table cell's default margins in inches, `[top, right, bottom, left]`: the schema defaults of\n// `a:tcPr`, which are PowerPoint's \"Normal\" margins (\"Narrow\" is `0.05` for all 4). 45720/914400\n// and 91440/914400 are exactly the doubles 0.05 and 0.1.\nexport const DEF_CELL_MARGIN_IN: [number, number, number, number] = [\n\tTABLE_CELL_MARGIN_DEFAULTS_EMU.top / EMU_PER_INCH,\n\tTABLE_CELL_MARGIN_DEFAULTS_EMU.right / EMU_PER_INCH,\n\tTABLE_CELL_MARGIN_DEFAULTS_EMU.bottom / EMU_PER_INCH,\n\tTABLE_CELL_MARGIN_DEFAULTS_EMU.left / EMU_PER_INCH,\n]\n// `satisfies` for the same reason as DEF_CELL_BORDER above.\nexport const DEF_CHART_BORDER = { type: 'solid', color: '363636', width: 1 } as const satisfies BorderProps\nexport const DEF_CHART_GRIDLINE: OptsChartGridLine = { color: '888888', dashType: 'solid', width: 1, cap: 'flat' }\nexport const DEF_FONT_COLOR = '000000'\nexport const DEF_FONT_SIZE = 12\n/**\n * The bounds of `ST_TextFontSize`, in points: the smallest and largest size an `a:rPr@sz` or an\n * `a:defRPr@sz` can carry. PowerPoint reports a package outside them as needing repair.\n *\n * Here rather than beside the clamp that enforces them (`gen/drawingml/clamp.ts`) because the\n * measured-fit pass needs the minimum too, to stop shrinking a cell before it goes out of range,\n * and `measure` is a published entry point: importing the clamp module for one number pulled the\n * whole of it into that bundle. Two plain numbers inline instead, and the clamp derives its own\n * range from them, so there is still one place the bound is stated.\n */\nexport const MIN_FONT_SIZE_PT = 1\nexport const MAX_FONT_SIZE_PT = 4000\nexport const DEF_FONT_TITLE_SIZE = 18\nexport const DEF_PRES_LAYOUT = 'LAYOUT_16x9'\nexport const DEF_PRES_LAYOUT_NAME = 'DEFAULT'\nexport const DEF_SHAPE_LINE_COLOR = '333333'\nexport const DEF_SHAPE_SHADOW: ShadowPropsInternal = {\n\ttype: 'outer',\n\tblur: 3,\n\toffset: 23000 / EMU_PER_POINT,\n\tangle: 90,\n\tcolor: '000000',\n\t_alpha: 0.35,\n\trotateWithShape: true,\n}\nexport const DEF_SLIDE_MARGIN_IN: [number, number, number, number] = [0.5, 0.5, 0.5, 0.5] // TRBL-style\nexport const DEF_TEXT_SHADOW: ShadowPropsInternal = {\n\ttype: 'outer',\n\tblur: 8,\n\toffset: 4,\n\tangle: 270,\n\tcolor: '000000',\n\t_alpha: 0.75,\n}\nexport const DEF_TEXT_GLOW = { size: 8, color: 'FFFFFF', opacity: 0.75 }\n\n// Fixed `<c:axId val>` identifiers that wire each chart's axes together (e.g. a value\n// axis's `<c:crossAx>` points at its category axis by id). ECMA-376 only requires the id\n// be a unique unsigned int within the chart; these stable constants keep the emitted\n// cross-references deterministic across decks. Consumed throughout `gen/chart/`.\nexport const AXIS_ID_VALUE_PRIMARY = '2094734552'\nexport const AXIS_ID_VALUE_SECONDARY = '2094734553'\nexport const AXIS_ID_CATEGORY_PRIMARY = '2094734554'\nexport const AXIS_ID_CATEGORY_SECONDARY = '2094734555'\nexport const AXIS_ID_SERIES_PRIMARY = '2094734556'\n\nexport const LETTERS: string[] = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')\n// The default series palettes hold their distinct entries once. Every consumer reaches them\n// through `paletteColor()` (`gen/chart/chart-parts.ts`), which wraps back to the start, so a\n// chart with more series or points than the palette has entries repeats it rather than\n// running off the end.\nexport const BARCHART_COLORS: string[] = [\n\t'C0504D',\n\t'4F81BD',\n\t'9BBB59',\n\t'8064A2',\n\t'4BACC6',\n\t'F79646',\n\t'628FC6',\n\t'C86360',\n]\nexport const PIECHART_COLORS: string[] = [\n\t'5DA5DA',\n\t'FAA43A',\n\t'60BD68',\n\t'F17CB0',\n\t'B2912F',\n\t'B276B2',\n\t'DECF3F',\n\t'F15854',\n\t'A7A7A7',\n]\n\n// Fixed GUID PowerPoint stamps on a slide-number field: `<a:fld id=\"{...}\" type=\"slidenum\">`.\n// Microsoft-specific (not defined by ECMA-376); reused verbatim so PowerPoint recognizes the\n// field and auto-updates the page number. Consumed in `gen/slide/object.ts` (`slideObjectToXml`).\nexport const SLDNUMFLDID = '{F7021451-1387-4CA6-816F-3879F97B5CBC}'\n\n// Cached text of a slide-number field on a part that has no slide number of its own — a master\n// or a layout. Guillemets around a hash, which is verbatim what PowerPoint caches there: every\n// en-US master and layout in `test/read/fixtures/` writes `<a:t>‹#›</a:t>`. (A German-locale\n// deck writes `‹Nr.›`; the cache is recomputed on open, so the en-US spelling is the one to\n// emit rather than a per-locale table.) Consumed in `gen/slide/object.ts`.\nexport const SLDNUM_PLACEHOLDER_TEXT = '‹#›'\n\n// The XML prolog every emitted OOXML part begins with. It lives in `ooxml/` so the read side's\n// serializers use the same one; re-exported for the generators that import it from here.\nexport { XML_DECL } from './ooxml/xml-decl.js'\n\n/**\n * The nine list levels' default left margins (`a:lvlNpPr/@marL`), half an inch apart.\n *\n * `p:txStyles`' body and other styles, `p:notesStyle` and the presentation's\n * `p:defaultTextStyle` are four separate ladders in the file and one ladder in fact: the\n * three modules that emit them each carried their own copy of these nine numbers, so a\n * level's margin could only be changed in one of them by accident.\n */\nexport const LEVEL_MARGINS_EMU: readonly number[] = Array.from({ length: 9 }, (_, i) => i * (EMU_PER_INCH / 2))\n\n/**\n * The paragraph-property tail every default `a:lvlNpPr` carries, whatever else it sets.\n *\n * Spread it *after* the level's own attributes: `el()` emits in `Object.entries` order, so\n * where these land in the tag is byte-significant, and every emitting site puts `marL` (and\n * where it has one, `indent` and `algn`) ahead of them.\n *\n * `algn` is deliberately not in here even though three of the four sites write `algn=\"l\"`.\n * The fourth computes it per level — a configured master's title can be centred or right —\n * and a spread that carried `algn` would silently overwrite that: a later key in an object\n * literal replaces the value without moving the key, so the attribute order would still look\n * right while the alignment was wrong. No gate deck configures a master text style, so\n * `byte-identity` cannot see that path; `master-text-styles.test.ts` pins it instead.\n */\nexport const LEVEL_PPR_TAIL = {\n\tdefTabSz: EMU_PER_INCH,\n\trtl: 0,\n\teaLnBrk: 1,\n\tlatinLnBrk: 0,\n\thangingPunct: 1,\n} as const\n","/**\n * Generator-side unit conversion — the lenient layer over `units.ts`.\n *\n * `units.ts` holds the strict, public primitives: one branded `Emu` type and converters that\n * take a number and throw on anything they cannot represent. This module holds what the\n * generators actually need on top of that: converters that accept the loose shapes the\n * authoring API has always accepted (numeric strings, `\"5in\"`, `null`), that clamp to the\n * ranges PowerPoint will load without offering to repair the file, and that warn about legacy\n * inputs instead of failing.\n *\n * The split is deliberate: the leniency and the back-compat warnings are policy, not\n * arithmetic, and policy should not be part of the published API. Nothing here is exported\n * from an entrypoint.\n */\n\nimport { DEF_CELL_MARGIN_IN, DEF_SLIDE_MARGIN_IN, LINEH_MODIFIER } from './constants-internal.js'\nimport { warn, warnOnce } from './diagnostics.js'\nimport { InvalidOptionError } from './errors.js'\nimport {\n\tEMU_PER_INCH,\n\tEMU_PER_POINT,\n\tANGLE_UNITS_PER_DEGREE,\n\tcoordToEmu,\n\tFIXED_PCT_PER_PERCENT,\n\tinchesToEmu,\n\tMAX_COORDINATE_EMU,\n\tPERCENT_SCALE,\n\ttype Emu,\n} from './units.js'\nimport type { DiagnosticCode, InvalidOptionErrorCode } from './codes.js'\nimport type { Coord, PresLayout } from './types/index.js'\n\n/**\n * Resolve a user `Coord` (x/y/w/h) to EMU — the single user-coordinate → EMU boundary.\n * - bare `number` → **inches** (no magnitude guessing); `\"<n>%\"` → percent of the slide axis;\n * `\"<n>in\"`/`\"<n>pt\"`/`\"<n>emu\"` → explicit units (see {@link Coord} / {@link coordToEmu})\n * - `null`/`undefined` → 0 (callers may omit a coordinate)\n * - throws on a non-finite number rather than silently collapsing the object to zero size\n * @param {Coord|null|undefined} size - user coordinate\n * @param {'X' | 'Y'} xyDir - axis (selects slide width vs height for percentages)\n * @param {PresLayout} layout - presentation layout (EMU dimensions)\n * @returns {Emu} resolved EMU value\n */\nexport function getSmartParseNumber(size: Coord | null | undefined, xyDir: 'X' | 'Y', layout: PresLayout): Emu {\n\tif (size === null || size === undefined) return 0 as Emu\n\n\t// GUARD: A NaN/Infinity coordinate is always a mistake (commonly arithmetic on an\n\t// `undefined` layout dimension). Fail loud with a targeted hint instead of the generic\n\t// converter message, since this is the most common way a deck collapses to zero-size.\n\tif (typeof size === 'number' && !Number.isFinite(size)) {\n\t\tthrow new InvalidOptionError(\n\t\t\t'coord/non-finite',\n\t\t\t`Invalid ${xyDir || 'coordinate'} value: expected a finite number but received ${String(size)}. ` +\n\t\t\t\t'This usually means a layout dimension was read from a missing property (e.g. `layout.width` returning `undefined`). ' +\n\t\t\t\t'Use `slide.width`/`slide.height` or `STANDARD_LAYOUTS.<NAME>.width`/`.height` (inches).'\n\t\t)\n\t}\n\n\treturn coordToEmu(size, xyDir === 'Y' ? layout.height : layout.width)\n}\n\n/**\n * Convert inches into EMU.\n * - accepts a number (inches) or a numeric/`\"<n>in\"` string\n * - no magnitude guessing: values are always treated as inches (use {@link coordToEmu} for\n * user coordinates that may carry other units)\n * @param {number|string} inches - inches as number or string\n * @returns {Emu} EMU value\n */\nexport function inch2Emu(inches: number | string): Emu {\n\tif (typeof inches === 'string') inches = Number(inches.replace(/in*/gi, ''))\n\treturn inchesToEmu(inches)\n}\n\n/**\n * Convert a single `margin` component (table cell/table margin, or text-box/placeholder body\n * inset) to EMU.\n *\n * Margins are INCHES, consistent with the positional API (`x`/`y`/`w`/`h`) and the value\n * PowerPoint's own dialog shows (both the table cell-margin and the text-box internal-margin\n * fields are inches). Historically the library read these as POINTS (table cells used a magnitude\n * heuristic — `>= 1` points, `< 1` inches; text-box margins were straight points), so a legitimate\n * fraction-of-an-inch value entered from the PowerPoint dialog became a tiny points value. Every\n * value is now inches. A `>= 1` value is honored as inches but warns once, because it is almost\n * certainly a legacy points value that should be divided by 72 (e.g. `10` points → `0.139` inches).\n *\n * Shared by every margin site so they stay in lockstep: the cell XML emitter and text-box/slide-\n * number insets (`gen/slide/object.ts`), the autoPage row-height pass (`gen/table/autopage.ts`), and the measured-fit pass\n * (`measure-fit`).\n * @param {number} inches - margin component in inches\n * @returns {Emu} EMU value\n */\nexport function marginToEmu(inches: number): Emu {\n\tif (inches >= 1)\n\t\twarnOnce(\n\t\t\t'margin/legacy-points',\n\t\t\t'margins (table cell and text-box) are interpreted as inches (matching the rest of the API and the ' +\n\t\t\t\t'PowerPoint dialog); a value >= 1 is likely a legacy points value — divide by 72 to convert (e.g. 10pt => 0.139in).'\n\t\t)\n\treturn inch2Emu(inches)\n}\n\n/**\n * A `[Top, Right, Bottom, Left]` margin (inches) as the four text insets in EMU, or `null` when\n * the caller stated no margin.\n *\n * A scalar broadcasts to all four sides. The index order is the whole point of naming this:\n * the arrays are CSS order while `a:bodyPr`/`a:tcPr` name their insets left-first, so every\n * site that mapped it by hand spelled the same 3/0/1/2 shuffle — the text box's `_bodyProp`,\n * the slide-number placeholder's `a:bodyPr`, and a table cell's `marL/R/T/B`.\n *\n * Each component goes through {@link marginToEmu}, so the legacy-points warning still fires\n * once for a value of an inch or more.\n * @param margin - the caller's `margin`, a scalar or a `[T, R, B, L]` array of inches\n */\nexport function resolveInsetsEmu(margin: number | number[] | undefined | null): {\n\tl: number\n\tt: number\n\tr: number\n\tb: number\n} | null {\n\tif (typeof margin === 'number') {\n\t\tconst all = marginToEmu(margin)\n\t\treturn { l: all, t: all, r: all, b: all }\n\t}\n\tif (!Array.isArray(margin)) return null\n\tconst at = (idx: number): number => marginToEmu(margin[idx] ?? 0)\n\treturn { l: at(3), t: at(0), r: at(1), b: at(2) }\n}\n\n/**\n * One line of table text, in EMU: `fontSizePt * (LINEH_MODIFIER + lineWeight) / 100`.\n *\n * The auto-pager prices a row by counting lines and multiplying by this, and the measured-fit\n * pass estimates a cell's height with the same product. Three sites wrote the expression by\n * hand and one of them left the caller's `autoPageLineWeight` out, so the pager guarded a row\n * against a line it then measured at a different height.\n *\n * @param fontSizePt - the resolved font size in points\n * @param lineWeight - the caller's `autoPageLineWeight`, an addend on the modifier\n */\nexport function autoPageLineHeightEmu(fontSizePt: number, lineWeight = 0): number {\n\treturn inch2Emu((fontSizePt * (LINEH_MODIFIER + lineWeight)) / 100)\n}\n\n/**\n * The four slide margins in inches, `[top, right, bottom, left]`, from the master's own margin\n * and the caller's `slideMargin`.\n *\n * Precedence is caller, then master, then {@link DEF_SLIDE_MARGIN_IN}. A scalar broadcasts to\n * all four sides; an array is taken as-is.\n *\n * Three sites derived this and they already disagreed. Two gated the master on\n * `typeof !== 'undefined'` and coerced with `Number.isFinite(Number(m))`; the HTML path gated\n * on truthiness and tested `Number.isFinite(m)` with no coercion. So a master with\n * `_margin: 0` took the master branch in two of them and the caller branch in the third, and\n * a master with `_margin: \"0.25\"` resolved in two and was ignored in the third.\n *\n * **The caller-first order was decided, the master-first one it replaced was not.** All three\n * pre-consolidation sites read the master first, inherited from upstream, and the consolidation\n * kept that order rather than deciding it -- so on a deck whose master defined a `margin`,\n * `addTable(rows, { slideMargin: 2 })` was discarded with nothing said, which is the reverse of\n * the rule stated everywhere else here: an explicit option beats an inherited one. The master's\n * `margin` is now the deck-wide default a per-table `slideMargin` overrides. A master margin as\n * a *floor* rather than a ceiling is a third reading, and if anyone needs it, it wants a stated\n * option rather than a precedence accident.\n *\n * @param masterMargin - the master/layout's `_margin`, in inches\n * @param slideMargin - the caller's `slideMargin`, in inches\n */\nexport function resolveSlideMarginsInches(\n\tmasterMargin: number | number[] | string | undefined | null,\n\tslideMargin?: number | number[] | string | null\n): [number, number, number, number] {\n\tconst broadcast = (value: number | number[] | string): [number, number, number, number] | null => {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst [t = 0, r = 0, b = 0, l = 0] = value\n\t\t\treturn [t, r, b, l]\n\t\t}\n\t\tconst n = Number(value)\n\t\treturn Number.isFinite(n) ? [n, n, n, n] : null\n\t}\n\tif (slideMargin !== undefined && slideMargin !== null) {\n\t\tconst resolved = broadcast(slideMargin)\n\t\tif (resolved) return resolved\n\t}\n\tif (masterMargin !== undefined && masterMargin !== null) {\n\t\tconst resolved = broadcast(masterMargin)\n\t\tif (resolved) return resolved\n\t}\n\treturn [...DEF_SLIDE_MARGIN_IN]\n}\n\n/**\n * Resolve a table's column widths to EMU, the single source of truth shared by the\n * table XML emitter and the measured-fit pass (so a fitted cell sees the same grid\n * the renderer draws).\n * - an explicit `colW` **array** is per-column inches (`inch2Emu`); a non-finite slot\n * falls back to the even-distribution width\n * - otherwise the table's already-resolved width (`totalWidthEmu`, EMU) is split evenly\n * across `colCount` columns. (A scalar `colW` never reaches here — `addTableDefinition`\n * converts it to `w` and clears `colW`.)\n *\n * IMPORTANT: the even path divides an **EMU** width. Passing the raw inches `options.w`\n * instead (the historical bug) produced ~0-EMU columns (e.g. `w=9` → `gridCol w=\"3\"`),\n * collapsing auto-width tables to a sliver in PowerPoint/LibreOffice.\n * @param {Coord[]|Coord|undefined} colW - explicit per-column inches, or scalar/undefined\n * @param {number} totalWidthEmu - the table's resolved width in EMU\n * @param {number} colCount - number of grid columns (counting colspans)\n * @returns {number[]} per-column widths in EMU (length `colCount`)\n */\nexport function resolveTableColWidthsEmu(\n\tcolW: Coord[] | Coord | undefined,\n\ttotalWidthEmu: number,\n\tcolCount: number\n): number[] {\n\tif (!(colCount > 0)) return []\n\tconst even = totalWidthEmu > 0 ? Math.round(totalWidthEmu / colCount) : EMU_PER_INCH\n\tif (Array.isArray(colW)) {\n\t\treturn Array.from({ length: colCount }, (_, i) => {\n\t\t\t// Guard before inch2Emu: it throws on non-finite input. A slot that is present but\n\t\t\t// unusable falls back to the even-distribution width AND says so, for the reason\n\t\t\t// `pinnedRowHeightInches` gives about the analogous `rowH` entry: it is something the\n\t\t\t// caller wrote on purpose and the even split is not what they meant. An absent slot is\n\t\t\t// not that — a sparse array is how a caller spells \"distribute this one\" — so it is\n\t\t\t// silent, which is the same line that helper draws.\n\t\t\tconst n = colW[i]\n\t\t\tif (typeof n === 'number' && Number.isFinite(n)) return Math.round(inch2Emu(n))\n\t\t\tif (n !== undefined && n !== null)\n\t\t\t\twarnOnce(\n\t\t\t\t\t'table/invalid-col-width',\n\t\t\t\t\t`colW entry ${String(n)} is not a number of inches; that column takes an even share of the table width instead.`\n\t\t\t\t)\n\t\t\treturn even\n\t\t})\n\t}\n\treturn new Array<number>(colCount).fill(even)\n}\n\n/**\n * The slide width a table may occupy, in EMU: the slide, less the table's own left\n * edge and the right slide margin.\n *\n * The width twin of the auto-pager's `calcSlideTabH`, and the same reading\n * `addTableDefinition` applies when a table states neither `w` nor `colW`. The pager\n * used to *add* the two margins here instead of subtracting them, which made its\n * fallback width about one inch however wide the slide was, and every column a sliver.\n *\n * @param presLayout - the presentation layout, for the slide width\n * @param xEmu - the table's resolved left edge in EMU; `0`/absent falls back to the left slide margin\n * @param marginsIn - the four slide margins in inches, as the pager holds them\n * @returns the usable width in EMU, never below zero\n */\nexport function usableTableWidthEmu(\n\tpresLayout: PresLayout,\n\txEmu: number,\n\tmarginsIn: readonly [number, number, number, number]\n): number {\n\t// `marginsIn` is TRBL, so the left margin is index 3 and the right one index 1. Both were\n\t// read one index off, which cancels out for a symmetric margin -- the default, and what every\n\t// gate deck sets -- and is wrong by their difference for anything else. `define/table.ts` had\n\t// already found and fixed this exact swap at its own sibling site.\n\tconst startIn = xEmu ? xEmu / EMU_PER_INCH : marginsIn[3]\n\treturn Math.max(0, presLayout.width - inch2Emu(startIn) - inch2Emu(marginsIn[1]))\n}\n\n/**\n * The single rule for whether one `rowH` entry pins a table row, in inches.\n *\n * An entry pins its row when it reads as a **finite number greater than zero**. Everything\n * else returns `null` — the row is sized from the table's own height, or grows to fit — and\n * an entry that is present but unusable warns, because `rowH: [0, …]` and `rowH: [-1, …]`\n * are things a caller wrote on purpose and none of the readings this replaced was what they\n * meant. A missing slot is not that: an array with holes is how the auto-pager spells\n * \"this row is auto-height\", so `undefined` is silent.\n *\n * Three call sites read `rowH` and they disagreed. The writer and the export-time fit pass\n * both used a truthiness test, so `0` fell through to the even split of `h`;\n * `pptx.tableLayout()` used `typeof === 'number'`, so `0` pinned the row at zero inches and\n * was then rescued by a default-line fallback — reporting 0.2in against the file's 2.0in,\n * and flagging it `heightExact`. A negative entry reached `<a:tr h=\"-914400\">`.\n *\n * @param entry - one `rowH` array slot, or the scalar `rowH`\n * @returns the pinned height in inches, or `null` when the row is not pinned by `rowH`\n */\nexport function pinnedRowHeightInches(entry: unknown): number | null {\n\tif (entry === undefined || entry === null) return null\n\tconst inches = Number(entry)\n\tif (Number.isFinite(inches) && inches > 0) return inches\n\twarnOnce(\n\t\t'table/invalid-row-height',\n\t\t`rowH entry ${String(entry)} is not a positive number of inches; the row is sized from the table height instead.`\n\t)\n\treturn null\n}\n\n/**\n * A table cell's `[Top, Right, Bottom, Left]` margins in inches, defaulted and validated.\n *\n * Three sites spelled this out -- two of them character-identical, the third self-described as\n * \"mirroring\" one of them -- and a fourth in the auto-pager gated each side on truthiness, so a\n * cell stating `margin: [0, …]` fell through to the table's margin instead of taking its own\n * zero. All of them swapped an unusable margin for the default in silence, while every sibling\n * resolver in this file warns for the same class of input.\n *\n * `resolveInsetsEmu` above is deliberately NOT a fifth copy: it resolves a text box's\n * `a:bodyPr` insets, where stating nothing means writing no attribute at all rather than\n * taking a cell default, so its absent case has a different answer.\n * @param margin - the caller's `margin`: a scalar, a `[T, R, B, L]` array, or nothing\n * @returns four finite inch measures\n */\nexport function resolveCellMarginsInches(\n\tmargin: number | number[] | undefined | null\n): [number, number, number, number] {\n\tif (margin === undefined || margin === null) return [...DEF_CELL_MARGIN_IN]\n\tconst usable = (value: unknown): boolean => typeof value === 'number' && Number.isFinite(value)\n\tif (typeof margin === 'number') {\n\t\tif (usable(margin)) return [margin, margin, margin, margin]\n\t} else if (Array.isArray(margin) && margin.length === 4 && margin.every(usable)) {\n\t\treturn [margin[0] as number, margin[1] as number, margin[2] as number, margin[3] as number]\n\t}\n\twarnOnce(\n\t\t'table/invalid-margin',\n\t\t`table margin ${JSON.stringify(margin)} is not a number of inches or a [top, right, bottom, left] array of four; using the default.`\n\t)\n\treturn [...DEF_CELL_MARGIN_IN]\n}\n\n/**\n * Resolve one table row's height to EMU — the row-height twin of\n * {@link resolveTableColWidthsEmu}, shared by the table XML emitter, the export-time\n * measured-fit pass and `pptx.tableLayout()` so a prediction cannot disagree with what the\n * export bakes.\n *\n * - a `rowH` entry that {@link pinnedRowHeightInches} accepts pins the row\n * - otherwise the table's already-resolved height (`totalHeightEmu`, EMU) is split evenly\n * across `rowCount` rows\n * - otherwise `null`: the row is auto-height and grows to fit its content\n *\n * @param rowH - the caller's `rowH`, scalar or per-row array\n * @param rowIndex - which row is being resolved\n * @param totalHeightEmu - the table's resolved height in EMU, or 0 when it has none\n * @param rowCount - number of rows to split that height across\n * @returns the row height in EMU, or `null` for an auto-height row\n */\nexport function resolveTableRowHeightEmu(\n\trowH: number | Array<number | null> | undefined,\n\trowIndex: number,\n\ttotalHeightEmu: number,\n\trowCount: number\n): number | null {\n\tconst pinned = pinnedRowHeightInches(Array.isArray(rowH) ? rowH[rowIndex] : rowH)\n\tif (pinned !== null) return Math.round(inch2Emu(pinned))\n\treturn totalHeightEmu > 0 && rowCount > 0 ? Math.round(totalHeightEmu / rowCount) : null\n}\n\n/**\n * Convert points to EMU, leniently: anything that does not read as a finite number — a `NaN`,\n * an `Infinity`, a non-numeric string, `null` — becomes `0` rather than throwing.\n *\n * That is the whole difference from {@link pointsToEmu} in `units.ts`, which throws on the same\n * input. Emitters use this one for the many optional size/width/offset options where a missing\n * or malformed value should collapse the feature (a zero-width line, no shadow offset) rather\n * than take the whole deck down.\n *\n * @param pt - points, as a number or a numeric string\n * @returns the value in EMU, or `0` if it does not read as a finite number\n */\nexport function ptsToEmuLenient(pt: number | string): number {\n\tconst points = Number(pt)\n\treturn Number.isFinite(points) ? Math.round(points * EMU_PER_POINT) : 0\n}\n\n/**\n * `fn(value)` for a numeric option the caller stated, `undefined` for one they did not.\n *\n * `null`, `undefined` and `0` are \"not stated\": an absent option and a zero one emit the same\n * thing (no `rot` for `rotate: 0`, the default width for `width: 0`). Every other value reaches\n * `fn`, `NaN` included, so the converter behind it decides what a value it cannot represent\n * means. The same test used to be spelled as truthiness, and `NaN` is falsy: it was dropped or\n * replaced by the default before the converter could refuse it, while `Infinity` on the same\n * option threw.\n * @param value - the caller's option\n * @param fn - the conversion to apply when the option is stated\n * @returns `fn(value)`, or `undefined` when the option is not stated\n */\nexport function mapStated<T extends number | string, R>(\n\tvalue: T | null | undefined,\n\tfn: (value: T) => R\n): R | undefined {\n\treturn value === null || value === undefined || value === 0 ? undefined : fn(value)\n}\n\n/**\n * Clamp a caller-supplied number into the range its schema type allows, warning when it had to\n * move. Returns the value in the caller's own unit — each helper below applies its own\n * arithmetic afterwards, because the inverting and non-inverting forms do not round alike.\n *\n * `NaN` throws rather than clamping: there is no nearest in-range value for it, and\n * `Math.min`/`Math.max` propagate it straight through to the attribute (`val=\"NaN\"`), which is\n * exactly the degenerate output the range check exists to prevent. `Infinity` is not in that\n * category — it clamps to the bound like any other out-of-range number, and warns.\n *\n * **This is the one policy for an out-of-range number**, and it is the policy\n * `docs/contributing/development.md` (\"Warn or throw?\") describes: a finite value has a nearest legal\n * neighbour, so the deck still comes out recognisable and the move is a warning; a value that\n * is not a number at all has no neighbour, so the request is discarded and that throws.\n * Rejecting a finite out-of-range value and emitting nothing is neither: it discards the request\n * and reports it as a warning, which is the combination the rule exists to rule out.\n *\n * Most of what passes through here is a percentage, which is why the throw names one by\n * default; `nonFiniteCode` is for the callers whose option is not one, such as a shadow's\n * angle in degrees.\n *\n * @param value - the caller's value\n * @param min - inclusive lower bound, in the caller's unit\n * @param max - inclusive upper bound, in the caller's unit\n * @param code - diagnostic code raised when the value is clamped\n * @param label - option name as the caller spells it, opening the warning\n * @param nonFiniteCode - error code thrown when the value is not a number at all\n * @param report - how a clamp is reported: `once` dedupes the warning on its code and message, as\n * a measure repeated across every run of a deck needs, and `range` states the range in the\n * caller's wording (`'1-4000pt'`) rather than as the two bare bounds\n */\nexport function clampRangedInput(\n\tvalue: number,\n\tmin: number,\n\tmax: number,\n\tcode: DiagnosticCode,\n\tlabel: string,\n\tnonFiniteCode: InvalidOptionErrorCode = 'percent/non-finite',\n\treport: { readonly once?: boolean; readonly range?: string } = {}\n): number {\n\tif (typeof value !== 'number' || Number.isNaN(value))\n\t\tthrow new InvalidOptionError(\n\t\t\tnonFiniteCode,\n\t\t\t`${label} must be a number from ${min} to ${max}; received ${String(value)}.`\n\t\t)\n\tconst clamped = Math.min(max, Math.max(min, value))\n\tif (clamped !== value) {\n\t\tconst message = `${label} ${value} is outside the valid range ${report.range ?? `${min}-${max}`}; using ${clamped}.`\n\t\tif (report.once) warnOnce(code, message)\n\t\telse warn(code, message)\n\t}\n\treturn clamped\n}\n\n/**\n * Convert a transparency percentage (0-100) into a schema-valid `<a:alpha>` value\n * (ST_PositiveFixedPercentage, 0-100000). Out-of-range transparency yields an\n * alpha that PowerPoint rejects as needing repair, so clamp into range and warn.\n *\n * This is the **inverting** form: 0 transparency is full opacity (`val=\"100000\"`). Use\n * {@link percentToFixedPercent} where the option already reads as opacity.\n */\nexport function transparencyToAlpha(transparency: number): number {\n\tconst pct = clampRangedInput(transparency, 0, 100, 'transparency/out-of-range', 'transparency')\n\treturn Math.round((100 - pct) * FIXED_PCT_PER_PERCENT)\n}\n\n/** Convert an opacity (0-1) into a schema-valid `<a:alpha>` value (0-100000); clamps + warns on out-of-range input. */\nexport function opacityToAlpha(opacity: number): number {\n\treturn fractionToFixedPercent(opacity, 'opacity/out-of-range', 'opacity')\n}\n\n/**\n * Convert a percentage into a schema-valid fixed-percentage value (thousandths of a percent) —\n * the **non-inverting** sibling of {@link transparencyToAlpha}, for options the caller already\n * states as \"how much\", such as a chart series' fill opacity.\n *\n * `min`/`max` default to the 0-100 nearly every such option allows. They are parameters because\n * the fixed-percentage attributes do not all share one range: `<a:buSzPct>` is\n * ST_TextBulletSizePercent (25-400), so the bullet-size option needs its own bounds while\n * keeping this function's policy.\n * @param value - the caller's percentage\n * @param code - diagnostic code raised when the value is clamped\n * @param label - option name as the caller spells it, opening the warning\n * @param min - inclusive lower bound in percent\n * @param max - inclusive upper bound in percent\n */\nexport function percentToFixedPercent(value: number, code: DiagnosticCode, label: string, min = 0, max = 100): number {\n\treturn Math.round(clampRangedInput(value, min, max, code, label) * FIXED_PCT_PER_PERCENT)\n}\n\n/**\n * Convert a 0-1 fraction into a schema-valid fixed-percentage value (0-100000), for the options\n * spelled as a fraction rather than a percentage (an opacity, a luminance threshold).\n * @param value - the caller's fraction\n * @param code - diagnostic code raised when the value is clamped\n * @param label - option name as the caller spells it, opening the warning\n */\nexport function fractionToFixedPercent(value: number, code: DiagnosticCode, label: string): number {\n\treturn Math.round(clampRangedInput(value, 0, 1, code, label) * PERCENT_SCALE)\n}\n\n/**\n * Convert a length stated in points to EMU, clamped into the schema range of the attribute it is\n * headed for.\n *\n * A number goes through {@link clampRangedInput}, the one policy for an out-of-range number: a\n * value past either bound clamps to it and warns, `Infinity` included, and `NaN` throws\n * `coord/non-finite`. Both of those used to collapse to `0` without a word, so `width: Infinity`\n * became a zero-width line while `width: 5000` clamped and warned.\n *\n * A value that does not read as a number at all, a string such as `'wide'`, still collapses the\n * feature to `0` via {@link ptsToEmuLenient}, because these are optional decorations on an object\n * that still has to be emitted. A numeric string past the range clamps and warns as before.\n *\n * @param pts - the caller's length in points, or any of the loose shapes `ptsToEmuLenient` takes\n * @param maxEmu - inclusive upper bound of the attribute's schema type, in EMU\n * @param code - diagnostic code raised when the value is clamped\n * @param label - option name as the caller spells it, opening the warning\n * @param range - the valid range in points, as the warning states it\n */\nfunction clampLengthEmu(\n\tpts: number | string,\n\tmaxEmu: number,\n\tcode: DiagnosticCode,\n\tlabel: string,\n\trange: string\n): number {\n\tif (typeof pts === 'number')\n\t\treturn Math.round(clampRangedInput(pts, 0, maxEmu / EMU_PER_POINT, code, label, 'coord/non-finite') * EMU_PER_POINT)\n\tconst raw = ptsToEmuLenient(pts)\n\tconst clamped = Math.min(maxEmu, Math.max(0, raw))\n\tif (clamped !== raw)\n\t\twarn(code, `${label} ${pts} is outside the valid range ${range}; using ${clamped / EMU_PER_POINT}.`)\n\treturn clamped\n}\n\n/**\n * Convert a line width (points) to EMU clamped into ST_LineWidth (0..20116800 EMU,\n * i.e. 0-1584pt). Out-of-range widths make PowerPoint report the package as needing\n * repair, so clamp into range and warn.\n *\n * `label` is what the refusal quotes back, the way {@link clampFontSizeSz} already names the nine\n * options that reach it. Every caller used to be reported as `line width`, so a `NaN` error-bar\n * `width` or a series `lineSize` threw \"line width must be a number from 0 to 1584\" and named\n * nothing the caller had written.\n * @param widthPts - the caller's width in points\n * @param label - the option as the caller spells it, e.g. `errorBars.width`\n */\nexport function lineWidthToEmu(widthPts: number | string, label = 'line width'): number {\n\treturn clampLengthEmu(widthPts, 20116800, 'line/width-out-of-range', label, '0-1584pt')\n}\n\n/**\n * Convert a shadow's blur radius or offset distance (points) to EMU clamped into\n * ST_PositiveCoordinate (0..27273042316900 EMU, i.e. 0-2147483647pt) — the type both\n * `blurRad` and `dist` carry on `a:outerShdw`/`a:innerShdw`.\n *\n * **The bound is the schema's, not the `0-100` / `0-200` those options document.** Those two\n * numbers are the limits of PowerPoint's own spinners, and a blur past them is unusual rather\n * than invalid: the file loads and paints. The one input that genuinely breaks the package is a\n * *negative* one, because the type is unsigned — so that is what this moves, on the same\n * reasoning `clampLineSpacingMultiplePct` in `gen/drawingml/clamp.ts` clamps to\n * ST_TextSpacingPercent rather than to the `0.0-9.99` its own option describes. Only values\n * PowerPoint reports as needing repair are worth moving.\n */\nexport function positiveCoordinateEmu(pts: number | string, code: DiagnosticCode, label: string): number {\n\treturn clampLengthEmu(pts, MAX_COORDINATE_EMU, code, label, '0-2147483647pt')\n}\n\n/**\n * Convert degrees to a DrawingML angle (60000ths of a degree), **without** wrapping.\n *\n * Most angles in the format are not modular: a connection site at 400 degrees, a polar adjust\n * handle whose range runs to 540, an arc that sweeps 400 degrees — each means something a\n * reduction into 0..360 would destroy. Use this for those, and {@link convertRotationDegrees}\n * for the ones that genuinely are a rotation.\n *\n * Non-finite input throws rather than reaching the attribute: `Math.round(Infinity * 60000)` is\n * `Infinity`, which serializes as `ang=\"Infinity\"` and makes PowerPoint offer to repair the file.\n *\n * @param d - degrees\n * @param what - what is being converted, for the error message\n * @param code - diagnostic code to throw under, where a caller has a more specific one\n */\nexport function convertAngleUnits(d: number, what: string, code: AngleErrorCode = 'coord/non-finite'): number {\n\tassertFiniteDegrees(d, what, code)\n\treturn Math.round(d * ANGLE_UNITS_PER_DEGREE)\n}\n\n/** The codes {@link convertAngleUnits} may throw under, each declared in `codes.ts`. */\ntype AngleErrorCode = 'coord/non-finite' | 'geometry/arc-angle-non-finite'\n\nfunction assertFiniteDegrees(d: number, what: string, code: AngleErrorCode): void {\n\tif (typeof d !== 'number' || !Number.isFinite(d))\n\t\tthrow new InvalidOptionError(code, `${what} must be a finite number of degrees; received ${String(d)}.`)\n}\n\n/**\n * Convert a shape or gradient rotation (degrees) to a DrawingML angle (60000ths of a degree).\n *\n * A rotation *is* modular — 800 degrees and 80 degrees point the same way — so the value is\n * reduced with `% 360`. The reduction keeps the sign: `-45` stays `-45` rather than becoming\n * `315`, because both are valid `ST_Angle`, PowerPoint writes negative rotations itself, and\n * the read side reports back what was authored. Only an input outside -360..360 moves.\n *\n * @param d - degrees\n * @returns the `rot` value in 60000ths of a degree\n */\nexport function convertRotationDegrees(d: number): number {\n\t// Guard before reducing, so `Infinity` is reported as itself rather than as the `NaN` that\n\t// `Infinity % 360` would hand on. No `d || 0` in front of it: that turned `NaN` into 0.\n\tassertFiniteDegrees(d, 'rotation', 'coord/non-finite')\n\treturn Math.round((d % 360) * ANGLE_UNITS_PER_DEGREE)\n}\n\n/**\n * Convert a freeform arc angle (degrees) to an `<a:arcTo>` ST_AdjAngle value (60000ths).\n * Unlike a shape rotation, a sweep is not modular: a 400 degree swAng draws a different\n * arc than a 40 degree one, so the value is never wrapped into 0..360.\n * @param {number} d degrees\n * @param {'stAng' | 'swAng'} attr - attribute being emitted, for the error message\n * @returns {number} ST_AdjAngle value (60000ths of a degree)\n */\nexport function convertArcAngle(d: number, attr: 'stAng' | 'swAng'): number {\n\treturn convertAngleUnits(d, `Arc ${attr}`, 'geometry/arc-angle-non-finite')\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { y as ZIP_OUTPUT_TYPE } from "./enums-
|
|
1
|
+
import { y as ZIP_OUTPUT_TYPE } from "./enums-DQRpVOLh.js";
|
|
2
2
|
//#region src/zip.d.ts
|
|
3
3
|
declare class ZipWriter {
|
|
4
4
|
#private;
|
|
@@ -64,4 +64,4 @@ type ZipInput = ZipInputValue | Promise<ZipInputValue>;
|
|
|
64
64
|
declare function readZip(input: ZipInput): Promise<Map<string, Uint8Array>>;
|
|
65
65
|
//#endregion
|
|
66
66
|
export { readZip as i, ZipInputValue as n, ZipWriter as r, ZipInput as t };
|
|
67
|
-
//# sourceMappingURL=zip-
|
|
67
|
+
//# sourceMappingURL=zip-CTll_dr0.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zip-
|
|
1
|
+
{"version":3,"file":"zip-CTll_dr0.d.ts","names":[],"sources":["../src/zip.ts"],"mappings":";;cAsCa;;;;;;;;EASZ,IAAI,cAAc,eAAe,YAAY;IAAS;;;;;;;;;;EAgBtD,WAAW;IAAQ;IAAc,MAAM;IAAY;;;;;;EAWnD,QAAQ,wBAAqB;;;;;;EAUvB,SACL,MAAM,iBACN;IAAQ;MACN,iBAAiB,cAAc,OAAO;;;;;;;;;;;;;;KAkB9B,oCAAoC,aAAa,cAAc;KAC/D,WAAW,gBAAgB,QAAQ;;;;;;;;;;iBAWzB,QAAQ,OAAO,WAAW,QAAQ,YAAY"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError } from "./errors-
|
|
1
|
+
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError } from "./errors-Da2nXCJm.js";
|
|
2
2
|
import { t as bytesToBinaryString } from "./binary-string-CKVAYI3M.js";
|
|
3
3
|
import { strToU8, unzipSync, zipSync } from "fflate";
|
|
4
4
|
//#region src/ooxml/pptx-content-type.ts
|
|
@@ -174,4 +174,4 @@ function convertZipOutput(bytes, type) {
|
|
|
174
174
|
//#endregion
|
|
175
175
|
export { readZip as n, PPTX_CONTENT_TYPE as r, ZipWriter as t };
|
|
176
176
|
|
|
177
|
-
//# sourceMappingURL=zip-
|
|
177
|
+
//# sourceMappingURL=zip-CYZ0F6BV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zip-CKd8ihcf.js","names":["exhaustive"],"sources":["../src/ooxml/pptx-content-type.ts","../src/zip.ts"],"sourcesContent":["/**\n * The content type of a `.pptx` file itself: what the `zip` entry and the browser download label\n * their Blob with, and what an OLE object declares for an embedded presentation.\n *\n * It is one of the content types `rel-types.ts` holds, and that module re-exports it. It has a\n * module of its own because the `zip` entry needs this one string and nothing else from that\n * table: imported from there, it handed the entry the whole table's chunk, about as many bytes\n * again as the entry itself, and pushed the entry past its size budget. Like the rest of `ooxml/`,\n * this module imports nothing.\n */\nexport const PPTX_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'\n","/**\n * Read and write zip archives on the backend the package itself uses: {@link readZip} unpacks\n * a `.pptx` (or any zip) to a map of paths to bytes, and {@link ZipWriter} builds one.\n *\n * @module\n */\nimport { strToU8, unzipSync, zipSync, type Unzipped, type Zippable, type ZipOptions } from 'fflate'\nimport type { ZIP_OUTPUT_TYPE } from './enums.js'\nimport { InvalidOptionError, PackageReadError, UnsupportedFeatureError } from './errors.js'\nimport { PPTX_CONTENT_TYPE } from './ooxml/pptx-content-type.js'\nimport { bytesToBinaryString } from './media/binary-string.js'\n\n/**\n * ZIP backend seam for the write path.\n *\n * fflate is functional — one `{path: bytes}` map in, one `Uint8Array` out — so\n * every contact with the backend is isolated here rather than spread across the\n * incremental builder calls the JSZip API encouraged. Callers accumulate entries\n * with {@link ZipWriter.add} (strings are UTF-8 encoded; already-decoded media\n * passes bytes directly) and finalize with {@link ZipWriter.generate}, which maps\n * fflate's single `Uint8Array` to the requested output shape.\n *\n * Unlike JSZip there is no folder/directory concept: keys are full slash-paths and\n * fflate emits no directory entries, so the package carries only real parts.\n */\n/**\n * Fixed modification time (2001-01-01, local midnight) stamped on every entry so archive\n * bytes are reproducible across runs. fflate encodes DOS dates, which are bounded\n * to 1980-2099, so 0/epoch is not usable here.\n *\n * Local time, not UTC, because a DOS date and time are wall-clock fields with no zone, and fflate\n * fills them from the local getters (`getFullYear`, `getHours`, …). A fixed local midnight reads\n * back as the same fields in every timezone. `Date.UTC(2001, 0, 1)` was one fixed instant, which\n * the getters render differently per zone: the header bytes moved with `TZ`, and west of UTC the\n * date rolled back to 2000-12-31.\n */\nconst FIXED_MTIME = new Date(2001, 0, 1)\n\nexport class ZipWriter {\n\treadonly #entries: Zippable = {}\n\n\t/**\n\t * Add a package part.\n\t * @param path - full zip path, e.g. `ppt/slides/slide1.xml`\n\t * @param data - XML string (UTF-8 encoded) or already-decoded bytes (media)\n\t * @param opts.store - skip DEFLATE for this entry (already-compressed media)\n\t */\n\tadd(path: string, data: string | Uint8Array, opts?: { store?: boolean }): void {\n\t\tconst bytes = typeof data === 'string' ? strToU8(data) : data\n\t\t// Pin mtime so archive bytes are reproducible across runs (stable fixtures).\n\t\tconst fileOpts: ZipOptions = { mtime: FIXED_MTIME }\n\t\tif (opts?.store) fileOpts.level = 0\n\t\tthis.#entries[path] = [bytes, fileOpts]\n\t}\n\n\t/**\n\t * Snapshot the accumulated entries in insertion order, before zipping. Each\n\t * entry carries its already-encoded bytes and whether it was added with\n\t * `store` (recovered from the per-entry level). This is the seam the\n\t * package-parts path reads: the same accumulator {@link generate} would zip,\n\t * exposed without running DEFLATE. Every value in `#entries` is the\n\t * `[bytes, opts]` tuple {@link add} writes, so the cast is total.\n\t */\n\tentries(): Array<{ path: string; data: Uint8Array; store: boolean }> {\n\t\treturn Object.entries(this.#entries).map(([path, value]) => {\n\t\t\tconst [bytes, fileOpts] = value as [Uint8Array, ZipOptions]\n\t\t\treturn { path, data: bytes, store: fileOpts.level === 0 }\n\t\t})\n\t}\n\n\t/**\n\t * Compress all accumulated entries to raw zip bytes.\n\t * @param compression - false stores every entry uncompressed (level 0)\n\t */\n\ttoBytes(compression = true): Uint8Array {\n\t\t// Global level is the per-entry default; entries added with `store` keep their level 0.\n\t\treturn zipSync(this.#entries, { level: compression ? 6 : 0, mtime: FIXED_MTIME })\n\t}\n\n\t/**\n\t * Finalize the archive in the requested output shape.\n\t * @param type - one of the supported {@link ZIP_OUTPUT_TYPE} output shapes\n\t * @param opts.compression - false stores every entry uncompressed\n\t */\n\tasync generate(\n\t\ttype: ZIP_OUTPUT_TYPE,\n\t\topts: { compression: boolean }\n\t): Promise<string | ArrayBuffer | Blob | Uint8Array> {\n\t\tconst bytes = this.toBytes(opts.compression)\n\t\treturn convertZipOutput(bytes, type)\n\t}\n}\n\n/**\n * Inputs the read path accepts. A `string` is a **filesystem path** (Node) read\n * from disk; in-memory archives are passed as `Uint8Array`/`ArrayBuffer`/`Blob`/\n * `number[]`. A `Promise` wrapper is allowed so callers can forward an unawaited\n * byte source.\n *\n * Note: unlike JSZip's `loadAsync`, a string is NOT a latin1 binary-content\n * string. That JSZip-compat interpretation was a footgun — every real consumer\n * passes a path, and a path silently became garbage bytes → \"Not a valid ZIP\n * archive\". To read a `binarystring`/`base64` write-path output back in, convert\n * it to bytes first (e.g. `Uint8Array.from(atob(b64), c => c.charCodeAt(0))`).\n */\nexport type ZipInputValue = string | number[] | Uint8Array | ArrayBuffer | Blob\nexport type ZipInput = ZipInputValue | Promise<ZipInputValue>\n\n/**\n * Decompress a zip archive to a `path → bytes` map in central-directory order.\n *\n * Read-path counterpart to {@link ZipWriter}: fflate's `unzipSync` needs a\n * `Uint8Array`, so the JSZip-style input auto-detection that `loadAsync` did is\n * reproduced by `toUint8Array` first. Directory markers (keys ending in\n * `/`) are dropped — fflate surfaces them but no consumer wants empty-dir\n * entries, and the write path emits none.\n */\nexport async function readZip(input: ZipInput): Promise<Map<string, Uint8Array>> {\n\tconst bytes = await toUint8Array(input)\n\tlet entries: Unzipped\n\ttry {\n\t\tentries = unzipSync(bytes)\n\t} catch (cause) {\n\t\tthrow new PackageReadError('zip/not-a-zip-archive', 'Not a valid ZIP archive', { cause })\n\t}\n\tconst out = new Map<string, Uint8Array>()\n\tfor (const [path, body] of Object.entries(entries)) {\n\t\tif (path.endsWith('/')) continue\n\t\tout.set(path, body)\n\t}\n\treturn out\n}\n\n/**\n * Normalize a read-path input to `Uint8Array`: a `Buffer`/`Uint8Array` passes\n * through, `ArrayBuffer`/`Blob`/`number[]` are copied/wrapped, and a `string` is\n * a **filesystem path** read from disk (Node). See {@link ZipInput} for why a\n * string is a path rather than JSZip's latin1 binary-content string.\n */\nasync function toUint8Array(input: ZipInput): Promise<Uint8Array> {\n\tconst data = await input\n\tif (data instanceof Uint8Array) return data\n\tif (data instanceof ArrayBuffer) return new Uint8Array(data)\n\tif (typeof data === 'string') return readFileAsBytes(data)\n\tif (Array.isArray(data)) return Uint8Array.from(data)\n\tif (typeof Blob !== 'undefined' && data instanceof Blob) return new Uint8Array(await data.arrayBuffer())\n\tthrow new InvalidOptionError(\n\t\t'zip/unsupported-input',\n\t\t'Unsupported zip input type; expected a filesystem path (string), number[], Uint8Array, ArrayBuffer, or Blob'\n\t)\n}\n\n/**\n * Read a `.pptx` (or any zip) from a filesystem path into bytes. Node-only:\n * `node:fs` is imported lazily so the browser build stays free of a Node\n * dependency, and a missing filesystem (browser) or missing file both throw a\n * clear error naming the path — never the opaque \"Not a valid ZIP archive\".\n */\nasync function readFileAsBytes(filePath: string): Promise<Uint8Array> {\n\tlet readFile: (typeof import('node:fs/promises'))['readFile']\n\ttry {\n\t\t;({ readFile } = await import('node:fs/promises'))\n\t} catch (cause) {\n\t\tthrow new UnsupportedFeatureError(\n\t\t\t'zip/filesystem-unavailable',\n\t\t\t`Cannot read zip from path \"${filePath}\": filesystem access requires Node. ` +\n\t\t\t\t'Pass a Uint8Array/ArrayBuffer/Blob for an in-memory archive.',\n\t\t\t{ cause }\n\t\t)\n\t}\n\ttry {\n\t\treturn new Uint8Array(await readFile(filePath))\n\t} catch (cause) {\n\t\tthrow new PackageReadError(\n\t\t\t'zip/file-read-failed',\n\t\t\t`Cannot read .pptx at \"${filePath}\": ${(cause as Error).message}`,\n\t\t\t{\n\t\t\t\tcause,\n\t\t\t}\n\t\t)\n\t}\n}\n\n/** Map fflate's `Uint8Array` to the requested {@link ZIP_OUTPUT_TYPE} output shape. */\nfunction convertZipOutput(bytes: Uint8Array, type: ZIP_OUTPUT_TYPE): string | ArrayBuffer | Blob | Uint8Array {\n\tswitch (type) {\n\t\tcase 'uint8array':\n\t\t\treturn bytes\n\t\tcase 'arraybuffer': {\n\t\t\t// Copy into a fresh (non-shared) ArrayBuffer; fflate's output buffer is\n\t\t\t// typed ArrayBufferLike, which may be a SharedArrayBuffer.\n\t\t\tconst out = new ArrayBuffer(bytes.byteLength)\n\t\t\tnew Uint8Array(out).set(bytes)\n\t\t\treturn out\n\t\t}\n\t\tcase 'nodebuffer':\n\t\t\t// Buffer.from(Uint8Array) copies, so the result owns its memory.\n\t\t\treturn Buffer.from(bytes)\n\t\tcase 'blob':\n\t\t\t// Copy into an ArrayBuffer-backed view so it is a valid BlobPart.\n\t\t\treturn new Blob([new Uint8Array(bytes)], { type: PPTX_CONTENT_TYPE })\n\t\tcase 'base64':\n\t\t\treturn btoa(bytesToBinaryString(bytes))\n\t\tcase 'binarystring':\n\t\t\treturn bytesToBinaryString(bytes)\n\t\tdefault: {\n\t\t\tconst exhaustive: never = type\n\t\t\tthrow new InvalidOptionError('zip/unsupported-output', `Unsupported zip output type: ${String(exhaustive)}`)\n\t\t}\n\t}\n}\n\n// Error taxonomy — see `entry-errors.ts`. Re-exported from every entry so `instanceof`\n// works whichever subpath a consumer imports.\nexport * from './entry-errors.js'\n\n// Diagnostics — see `entry-diagnostics.ts`. Re-exported from every entry so a consumer of any\n// subpath can install a handler for the warnings that subpath emits.\nexport * from './entry-diagnostics.js'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"zip-CYZ0F6BV.js","names":["exhaustive"],"sources":["../src/ooxml/pptx-content-type.ts","../src/zip.ts"],"sourcesContent":["/**\n * The content type of a `.pptx` file itself: what the `zip` entry and the browser download label\n * their Blob with, and what an OLE object declares for an embedded presentation.\n *\n * It is one of the content types `rel-types.ts` holds, and that module re-exports it. It has a\n * module of its own because the `zip` entry needs this one string and nothing else from that\n * table: imported from there, it handed the entry the whole table's chunk, about as many bytes\n * again as the entry itself, and pushed the entry past its size budget. Like the rest of `ooxml/`,\n * this module imports nothing.\n */\nexport const PPTX_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'\n","/**\n * Read and write zip archives on the backend the package itself uses: {@link readZip} unpacks\n * a `.pptx` (or any zip) to a map of paths to bytes, and {@link ZipWriter} builds one.\n *\n * @module\n */\nimport { strToU8, unzipSync, zipSync, type Unzipped, type Zippable, type ZipOptions } from 'fflate'\nimport type { ZIP_OUTPUT_TYPE } from './enums.js'\nimport { InvalidOptionError, PackageReadError, UnsupportedFeatureError } from './errors.js'\nimport { PPTX_CONTENT_TYPE } from './ooxml/pptx-content-type.js'\nimport { bytesToBinaryString } from './media/binary-string.js'\n\n/**\n * ZIP backend seam for the write path.\n *\n * fflate is functional — one `{path: bytes}` map in, one `Uint8Array` out — so\n * every contact with the backend is isolated here rather than spread across the\n * incremental builder calls the JSZip API encouraged. Callers accumulate entries\n * with {@link ZipWriter.add} (strings are UTF-8 encoded; already-decoded media\n * passes bytes directly) and finalize with {@link ZipWriter.generate}, which maps\n * fflate's single `Uint8Array` to the requested output shape.\n *\n * Unlike JSZip there is no folder/directory concept: keys are full slash-paths and\n * fflate emits no directory entries, so the package carries only real parts.\n */\n/**\n * Fixed modification time (2001-01-01, local midnight) stamped on every entry so archive\n * bytes are reproducible across runs. fflate encodes DOS dates, which are bounded\n * to 1980-2099, so 0/epoch is not usable here.\n *\n * Local time, not UTC, because a DOS date and time are wall-clock fields with no zone, and fflate\n * fills them from the local getters (`getFullYear`, `getHours`, …). A fixed local midnight reads\n * back as the same fields in every timezone. `Date.UTC(2001, 0, 1)` was one fixed instant, which\n * the getters render differently per zone: the header bytes moved with `TZ`, and west of UTC the\n * date rolled back to 2000-12-31.\n */\nconst FIXED_MTIME = new Date(2001, 0, 1)\n\nexport class ZipWriter {\n\treadonly #entries: Zippable = {}\n\n\t/**\n\t * Add a package part.\n\t * @param path - full zip path, e.g. `ppt/slides/slide1.xml`\n\t * @param data - XML string (UTF-8 encoded) or already-decoded bytes (media)\n\t * @param opts.store - skip DEFLATE for this entry (already-compressed media)\n\t */\n\tadd(path: string, data: string | Uint8Array, opts?: { store?: boolean }): void {\n\t\tconst bytes = typeof data === 'string' ? strToU8(data) : data\n\t\t// Pin mtime so archive bytes are reproducible across runs (stable fixtures).\n\t\tconst fileOpts: ZipOptions = { mtime: FIXED_MTIME }\n\t\tif (opts?.store) fileOpts.level = 0\n\t\tthis.#entries[path] = [bytes, fileOpts]\n\t}\n\n\t/**\n\t * Snapshot the accumulated entries in insertion order, before zipping. Each\n\t * entry carries its already-encoded bytes and whether it was added with\n\t * `store` (recovered from the per-entry level). This is the seam the\n\t * package-parts path reads: the same accumulator {@link generate} would zip,\n\t * exposed without running DEFLATE. Every value in `#entries` is the\n\t * `[bytes, opts]` tuple {@link add} writes, so the cast is total.\n\t */\n\tentries(): Array<{ path: string; data: Uint8Array; store: boolean }> {\n\t\treturn Object.entries(this.#entries).map(([path, value]) => {\n\t\t\tconst [bytes, fileOpts] = value as [Uint8Array, ZipOptions]\n\t\t\treturn { path, data: bytes, store: fileOpts.level === 0 }\n\t\t})\n\t}\n\n\t/**\n\t * Compress all accumulated entries to raw zip bytes.\n\t * @param compression - false stores every entry uncompressed (level 0)\n\t */\n\ttoBytes(compression = true): Uint8Array {\n\t\t// Global level is the per-entry default; entries added with `store` keep their level 0.\n\t\treturn zipSync(this.#entries, { level: compression ? 6 : 0, mtime: FIXED_MTIME })\n\t}\n\n\t/**\n\t * Finalize the archive in the requested output shape.\n\t * @param type - one of the supported {@link ZIP_OUTPUT_TYPE} output shapes\n\t * @param opts.compression - false stores every entry uncompressed\n\t */\n\tasync generate(\n\t\ttype: ZIP_OUTPUT_TYPE,\n\t\topts: { compression: boolean }\n\t): Promise<string | ArrayBuffer | Blob | Uint8Array> {\n\t\tconst bytes = this.toBytes(opts.compression)\n\t\treturn convertZipOutput(bytes, type)\n\t}\n}\n\n/**\n * Inputs the read path accepts. A `string` is a **filesystem path** (Node) read\n * from disk; in-memory archives are passed as `Uint8Array`/`ArrayBuffer`/`Blob`/\n * `number[]`. A `Promise` wrapper is allowed so callers can forward an unawaited\n * byte source.\n *\n * Note: unlike JSZip's `loadAsync`, a string is NOT a latin1 binary-content\n * string. That JSZip-compat interpretation was a footgun — every real consumer\n * passes a path, and a path silently became garbage bytes → \"Not a valid ZIP\n * archive\". To read a `binarystring`/`base64` write-path output back in, convert\n * it to bytes first (e.g. `Uint8Array.from(atob(b64), c => c.charCodeAt(0))`).\n */\nexport type ZipInputValue = string | number[] | Uint8Array | ArrayBuffer | Blob\nexport type ZipInput = ZipInputValue | Promise<ZipInputValue>\n\n/**\n * Decompress a zip archive to a `path → bytes` map in central-directory order.\n *\n * Read-path counterpart to {@link ZipWriter}: fflate's `unzipSync` needs a\n * `Uint8Array`, so the JSZip-style input auto-detection that `loadAsync` did is\n * reproduced by `toUint8Array` first. Directory markers (keys ending in\n * `/`) are dropped — fflate surfaces them but no consumer wants empty-dir\n * entries, and the write path emits none.\n */\nexport async function readZip(input: ZipInput): Promise<Map<string, Uint8Array>> {\n\tconst bytes = await toUint8Array(input)\n\tlet entries: Unzipped\n\ttry {\n\t\tentries = unzipSync(bytes)\n\t} catch (cause) {\n\t\tthrow new PackageReadError('zip/not-a-zip-archive', 'Not a valid ZIP archive', { cause })\n\t}\n\tconst out = new Map<string, Uint8Array>()\n\tfor (const [path, body] of Object.entries(entries)) {\n\t\tif (path.endsWith('/')) continue\n\t\tout.set(path, body)\n\t}\n\treturn out\n}\n\n/**\n * Normalize a read-path input to `Uint8Array`: a `Buffer`/`Uint8Array` passes\n * through, `ArrayBuffer`/`Blob`/`number[]` are copied/wrapped, and a `string` is\n * a **filesystem path** read from disk (Node). See {@link ZipInput} for why a\n * string is a path rather than JSZip's latin1 binary-content string.\n */\nasync function toUint8Array(input: ZipInput): Promise<Uint8Array> {\n\tconst data = await input\n\tif (data instanceof Uint8Array) return data\n\tif (data instanceof ArrayBuffer) return new Uint8Array(data)\n\tif (typeof data === 'string') return readFileAsBytes(data)\n\tif (Array.isArray(data)) return Uint8Array.from(data)\n\tif (typeof Blob !== 'undefined' && data instanceof Blob) return new Uint8Array(await data.arrayBuffer())\n\tthrow new InvalidOptionError(\n\t\t'zip/unsupported-input',\n\t\t'Unsupported zip input type; expected a filesystem path (string), number[], Uint8Array, ArrayBuffer, or Blob'\n\t)\n}\n\n/**\n * Read a `.pptx` (or any zip) from a filesystem path into bytes. Node-only:\n * `node:fs` is imported lazily so the browser build stays free of a Node\n * dependency, and a missing filesystem (browser) or missing file both throw a\n * clear error naming the path — never the opaque \"Not a valid ZIP archive\".\n */\nasync function readFileAsBytes(filePath: string): Promise<Uint8Array> {\n\tlet readFile: (typeof import('node:fs/promises'))['readFile']\n\ttry {\n\t\t;({ readFile } = await import('node:fs/promises'))\n\t} catch (cause) {\n\t\tthrow new UnsupportedFeatureError(\n\t\t\t'zip/filesystem-unavailable',\n\t\t\t`Cannot read zip from path \"${filePath}\": filesystem access requires Node. ` +\n\t\t\t\t'Pass a Uint8Array/ArrayBuffer/Blob for an in-memory archive.',\n\t\t\t{ cause }\n\t\t)\n\t}\n\ttry {\n\t\treturn new Uint8Array(await readFile(filePath))\n\t} catch (cause) {\n\t\tthrow new PackageReadError(\n\t\t\t'zip/file-read-failed',\n\t\t\t`Cannot read .pptx at \"${filePath}\": ${(cause as Error).message}`,\n\t\t\t{\n\t\t\t\tcause,\n\t\t\t}\n\t\t)\n\t}\n}\n\n/** Map fflate's `Uint8Array` to the requested {@link ZIP_OUTPUT_TYPE} output shape. */\nfunction convertZipOutput(bytes: Uint8Array, type: ZIP_OUTPUT_TYPE): string | ArrayBuffer | Blob | Uint8Array {\n\tswitch (type) {\n\t\tcase 'uint8array':\n\t\t\treturn bytes\n\t\tcase 'arraybuffer': {\n\t\t\t// Copy into a fresh (non-shared) ArrayBuffer; fflate's output buffer is\n\t\t\t// typed ArrayBufferLike, which may be a SharedArrayBuffer.\n\t\t\tconst out = new ArrayBuffer(bytes.byteLength)\n\t\t\tnew Uint8Array(out).set(bytes)\n\t\t\treturn out\n\t\t}\n\t\tcase 'nodebuffer':\n\t\t\t// Buffer.from(Uint8Array) copies, so the result owns its memory.\n\t\t\treturn Buffer.from(bytes)\n\t\tcase 'blob':\n\t\t\t// Copy into an ArrayBuffer-backed view so it is a valid BlobPart.\n\t\t\treturn new Blob([new Uint8Array(bytes)], { type: PPTX_CONTENT_TYPE })\n\t\tcase 'base64':\n\t\t\treturn btoa(bytesToBinaryString(bytes))\n\t\tcase 'binarystring':\n\t\t\treturn bytesToBinaryString(bytes)\n\t\tdefault: {\n\t\t\tconst exhaustive: never = type\n\t\t\tthrow new InvalidOptionError('zip/unsupported-output', `Unsupported zip output type: ${String(exhaustive)}`)\n\t\t}\n\t}\n}\n\n// Error taxonomy — see `entry-errors.ts`. Re-exported from every entry so `instanceof`\n// works whichever subpath a consumer imports.\nexport * from './entry-errors.js'\n\n// Diagnostics — see `entry-diagnostics.ts`. Re-exported from every entry so a consumer of any\n// subpath can install a handler for the warnings that subpath emits.\nexport * from './entry-diagnostics.js'\n"],"mappings":"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"}
|
package/dist/zip.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as PackageReadErrorCode, a as InternalError, c as PackageReadError, d as UnsupportedFeatureError, f as DiagnosticCode, g as MediaErrorCode, h as InvalidOptionErrorCode, i as setDiagnosticHandler, l as TsPptxError, m as InternalErrorCode, n as DiagnosticHandler, o as InvalidOptionError, p as ErrorCode, r as resetDiagnosticState, s as MediaError, t as Diagnostic, u as TsPptxErrorOptions, v as TsPptxCode, y as UnsupportedFeatureErrorCode } from "./diagnostics-
|
|
2
|
-
import { i as readZip, n as ZipInputValue, r as ZipWriter, t as ZipInput } from "./zip-
|
|
1
|
+
import { _ as PackageReadErrorCode, a as InternalError, c as PackageReadError, d as UnsupportedFeatureError, f as DiagnosticCode, g as MediaErrorCode, h as InvalidOptionErrorCode, i as setDiagnosticHandler, l as TsPptxError, m as InternalErrorCode, n as DiagnosticHandler, o as InvalidOptionError, p as ErrorCode, r as resetDiagnosticState, s as MediaError, t as Diagnostic, u as TsPptxErrorOptions, v as TsPptxCode, y as UnsupportedFeatureErrorCode } from "./diagnostics-DiMmBU8P.js";
|
|
2
|
+
import { i as readZip, n as ZipInputValue, r as ZipWriter, t as ZipInput } from "./zip-CTll_dr0.js";
|
|
3
3
|
export { type Diagnostic, type DiagnosticCode, type DiagnosticHandler, type ErrorCode, InternalError, type InternalErrorCode, InvalidOptionError, type InvalidOptionErrorCode, MediaError, type MediaErrorCode, PackageReadError, type PackageReadErrorCode, type TsPptxCode, TsPptxError, type TsPptxErrorOptions, UnsupportedFeatureError, type UnsupportedFeatureErrorCode, ZipInput, ZipInputValue, ZipWriter, readZip, resetDiagnosticState, setDiagnosticHandler };
|
package/dist/zip.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as TsPptxError, c as setDiagnosticHandler, i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, s as resetDiagnosticState, t as InternalError } from "./errors-
|
|
2
|
-
import { n as readZip, t as ZipWriter } from "./zip-
|
|
1
|
+
import { a as TsPptxError, c as setDiagnosticHandler, i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, s as resetDiagnosticState, t as InternalError } from "./errors-Da2nXCJm.js";
|
|
2
|
+
import { n as readZip, t as ZipWriter } from "./zip-CYZ0F6BV.js";
|
|
3
3
|
export { InternalError, InvalidOptionError, MediaError, PackageReadError, TsPptxError, UnsupportedFeatureError, ZipWriter, readZip, resetDiagnosticState, setDiagnosticHandler };
|