pptx-ts 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +319 -0
- package/dist/autopage-DkjYZUFD.js +423 -0
- package/dist/autopage-DkjYZUFD.js.map +1 -0
- package/dist/browser.d.ts +31 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +110 -0
- package/dist/browser.js.map +1 -0
- package/dist/diagnostics-Du_s75MT.d.ts +829 -0
- package/dist/diagnostics-Du_s75MT.d.ts.map +1 -0
- package/dist/enums-CvRYniUA.d.ts +463 -0
- package/dist/enums-CvRYniUA.d.ts.map +1 -0
- package/dist/errors-Bvln0H-7.js +112 -0
- package/dist/errors-Bvln0H-7.js.map +1 -0
- package/dist/errors-PflMPWBn.d.ts +182 -0
- package/dist/errors-PflMPWBn.d.ts.map +1 -0
- package/dist/fit-BKs0zxMI.js +1356 -0
- package/dist/fit-BKs0zxMI.js.map +1 -0
- package/dist/html-dom-B0I0QSbU.js +679 -0
- package/dist/html-dom-B0I0QSbU.js.map +1 -0
- package/dist/html.d.ts +26 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +63 -0
- package/dist/html.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +197 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +317 -0
- package/dist/inspect.js.map +1 -0
- package/dist/math.d.ts +37 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.js +203 -0
- package/dist/math.js.map +1 -0
- package/dist/measure.d.ts +313 -0
- package/dist/measure.d.ts.map +1 -0
- package/dist/measure.js +3 -0
- package/dist/namespaces-BVnNu7sg.js +666 -0
- package/dist/namespaces-BVnNu7sg.js.map +1 -0
- package/dist/node.d.ts +20 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +55 -0
- package/dist/node.js.map +1 -0
- package/dist/notes-RLCwdlTE.js +1703 -0
- package/dist/notes-RLCwdlTE.js.map +1 -0
- package/dist/package-CaOLXSNi.d.ts +193 -0
- package/dist/package-CaOLXSNi.d.ts.map +1 -0
- package/dist/pres-C5__xkDh.d.ts +202 -0
- package/dist/pres-C5__xkDh.d.ts.map +1 -0
- package/dist/presentation-Cp7vzlAw.js +5427 -0
- package/dist/presentation-Cp7vzlAw.js.map +1 -0
- package/dist/presentation-types-DP_8jog7.d.ts +4872 -0
- package/dist/presentation-types-DP_8jog7.d.ts.map +1 -0
- package/dist/read.d.ts +55 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +4 -0
- package/dist/script.d.ts +581 -0
- package/dist/script.d.ts.map +1 -0
- package/dist/script.js +3741 -0
- package/dist/script.js.map +1 -0
- package/dist/shapes-BemroU-z.js +6951 -0
- package/dist/shapes-BemroU-z.js.map +1 -0
- package/dist/slide-js0QpRV-.d.ts +3873 -0
- package/dist/slide-js0QpRV-.d.ts.map +1 -0
- package/dist/text-CyetbF6p.js +11278 -0
- package/dist/text-CyetbF6p.js.map +1 -0
- package/dist/units-1kRzYShk.js +231 -0
- package/dist/units-1kRzYShk.js.map +1 -0
- package/dist/units-internal-Dg95w_YD.js +753 -0
- package/dist/units-internal-Dg95w_YD.js.map +1 -0
- package/dist/zip.d.ts +68 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +163 -0
- package/dist/zip.js.map +1 -0
- package/package.json +152 -0
- package/skills/ts-pptx-upstream/SKILL.md +340 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { n as InvalidOptionError } from "./errors-Bvln0H-7.js";
|
|
2
|
+
//#region src/diagnostics.ts
|
|
3
|
+
/** Prefix stamped on every warning so consumers can attribute console noise to this library. */
|
|
4
|
+
const WARN_PREFIX = "ts-pptx";
|
|
5
|
+
/** The default handler: one `console.warn` line per diagnostic, prefixed. */
|
|
6
|
+
const consoleHandler = (diagnostic) => {
|
|
7
|
+
console.warn(`${WARN_PREFIX}: ${diagnostic.message}`);
|
|
8
|
+
};
|
|
9
|
+
let handler = consoleHandler;
|
|
10
|
+
/**
|
|
11
|
+
* Route every library diagnostic to `handler`, or pass `null` to restore the default
|
|
12
|
+
* (one prefixed `console.warn` per diagnostic).
|
|
13
|
+
*
|
|
14
|
+
* This is process-global rather than per-presentation, deliberately: the emitting code is a tree
|
|
15
|
+
* of free functions in `gen/**` with no presentation in scope, and threading a handler through
|
|
16
|
+
* every signature would be a far larger and worse change than the problem warrants. The practical
|
|
17
|
+
* consequence is that a process building several decks concurrently cannot attribute a diagnostic
|
|
18
|
+
* to one of them; if that matters, correlate on `code` or set the handler around each build.
|
|
19
|
+
*
|
|
20
|
+
* A throwing handler propagates out of whatever library call emitted the diagnostic, which is the
|
|
21
|
+
* supported way to make a specific condition fatal:
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* setDiagnosticHandler((d) => {
|
|
25
|
+
* if (d.code === 'coord/bare-number-is-inches') throw new Error(d.message)
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
* @param next - the receiver, or `null` to restore the console default
|
|
29
|
+
*/
|
|
30
|
+
function setDiagnosticHandler(next) {
|
|
31
|
+
handler = next ?? consoleHandler;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Emit a library diagnostic.
|
|
35
|
+
* @param code - the stable condition identifier ({@link DiagnosticCode})
|
|
36
|
+
* @param message - explanation, without a `ts-pptx:` prefix (the default handler adds one)
|
|
37
|
+
* @param detail - optional structured context
|
|
38
|
+
*/
|
|
39
|
+
function warn(code, message, detail) {
|
|
40
|
+
handler(detail === void 0 ? {
|
|
41
|
+
code,
|
|
42
|
+
message
|
|
43
|
+
} : {
|
|
44
|
+
code,
|
|
45
|
+
message,
|
|
46
|
+
detail
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50
|
+
/**
|
|
51
|
+
* Emit a library diagnostic at most once per distinct code+message.
|
|
52
|
+
*
|
|
53
|
+
* "Once" is **process-global**, the same scope {@link setDiagnosticHandler} has and for the
|
|
54
|
+
* same reason: the emitting code is a tree of free functions in `gen/**` with no presentation
|
|
55
|
+
* in scope. The consequence is different, though, and worth stating on its own — a process that
|
|
56
|
+
* builds several decks does not get a second report of a condition an earlier deck already
|
|
57
|
+
* tripped, so the second deck's diagnostics are incomplete rather than merely unattributed.
|
|
58
|
+
* {@link resetDiagnosticState} is how a host that cares gets each build a clean slate.
|
|
59
|
+
*
|
|
60
|
+
* @param code - the stable condition identifier ({@link DiagnosticCode})
|
|
61
|
+
* @param message - explanation (see {@link warn})
|
|
62
|
+
* @param detail - optional structured context
|
|
63
|
+
*/
|
|
64
|
+
function warnOnce(code, message, detail) {
|
|
65
|
+
const key = `${code}\0${message}`;
|
|
66
|
+
if (seen.has(key)) return;
|
|
67
|
+
seen.add(key);
|
|
68
|
+
warn(code, message, detail);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clear the {@link warnOnce} dedupe set, so a condition already reported reports again.
|
|
72
|
+
*
|
|
73
|
+
* Call it between builds in a host that builds more than one deck per process and wants each
|
|
74
|
+
* build's diagnostics complete. Without it, deck two is silent about anything deck one already
|
|
75
|
+
* warned for, which reads as "no problems found" rather than as "already mentioned".
|
|
76
|
+
*
|
|
77
|
+
* It also bounds the set. Most `warnOnce` messages interpolate the offending value, so a server
|
|
78
|
+
* building decks from user input accumulates one entry per distinct bad value with no way to
|
|
79
|
+
* release them.
|
|
80
|
+
*
|
|
81
|
+
* This does not touch the handler — {@link setDiagnosticHandler} owns that, and the two are
|
|
82
|
+
* reset independently on purpose: a host usually installs its handler once and wants it to
|
|
83
|
+
* survive.
|
|
84
|
+
*/
|
|
85
|
+
function resetDiagnosticState() {
|
|
86
|
+
seen.clear();
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/units.ts
|
|
90
|
+
/**
|
|
91
|
+
* Public unit conversion helpers and standard PowerPoint slide-layout constants.
|
|
92
|
+
*/
|
|
93
|
+
const EMU_PER_INCH = 914400;
|
|
94
|
+
const EMU_PER_POINT = 12700;
|
|
95
|
+
const POINTS_PER_INCH = 72;
|
|
96
|
+
/**
|
|
97
|
+
* DrawingML angle unit. `ST_Angle` (`rot`, shadow `dir`, gradient `ang`, …) is measured in
|
|
98
|
+
* sixtieths-of-a-thousandth of a degree, i.e. 60000 units per degree. Multiply a value in
|
|
99
|
+
* degrees by this to get the OOXML integer.
|
|
100
|
+
*/
|
|
101
|
+
const ANGLE_UNITS_PER_DEGREE = 6e4;
|
|
102
|
+
/**
|
|
103
|
+
* DrawingML fixed-point percentage scale. `ST_Percentage` / `ST_PositiveFixedPercentage` and
|
|
104
|
+
* related types (`<a:alpha>`, `<a:spcPct>`, shape adjustment guides, `<p:tav tm>`, …) encode
|
|
105
|
+
* 100% as the integer 100000. Multiply a 0-1 fraction by this to get the OOXML value.
|
|
106
|
+
*/
|
|
107
|
+
const PERCENT_SCALE = 1e5;
|
|
108
|
+
/**
|
|
109
|
+
* Scale for a percentage supplied as 0-100 (rather than a 0-1 fraction) into the same
|
|
110
|
+
* fixed-point percentage integer as {@link PERCENT_SCALE} (1% = 1000 units, i.e. thousandths
|
|
111
|
+
* of a percent). Use for inputs documented as percents: transparency/alpha, image crop insets,
|
|
112
|
+
* gradient stops, bullet size, connector adjust, etc.
|
|
113
|
+
*/
|
|
114
|
+
const FIXED_PCT_PER_PERCENT = PERCENT_SCALE / 100;
|
|
115
|
+
/**
|
|
116
|
+
* DrawingML text measures font size (`sz`), character spacing (`spc`) and point line/paragraph
|
|
117
|
+
* spacing (`<a:spcPts val>`) in hundredths of a point. Multiply a value in points by this to get
|
|
118
|
+
* the OOXML integer.
|
|
119
|
+
*/
|
|
120
|
+
const HUNDREDTHS_PER_POINT = 100;
|
|
121
|
+
/**
|
|
122
|
+
* Convert a value in points to hundredths of a point (rounded), the integer unit DrawingML uses
|
|
123
|
+
* for `sz`, `spc`, and `<a:spcPts val>`. See {@link HUNDREDTHS_PER_POINT}.
|
|
124
|
+
*/
|
|
125
|
+
function ptToHundredths(pt) {
|
|
126
|
+
assertFiniteNumber(pt, "points");
|
|
127
|
+
return Math.round(pt * 100);
|
|
128
|
+
}
|
|
129
|
+
/** A bare number larger than this (in inches) is almost certainly a mistake — likely a raw EMU
|
|
130
|
+
* value passed where inches are expected. We interpret it as inches (the documented contract) but
|
|
131
|
+
* warn, pointing at the explicit `"<n>emu"` form. ~1000in is far beyond any real slide. */
|
|
132
|
+
const IMPLAUSIBLE_INCHES = 1e3;
|
|
133
|
+
/** Default pixel density for the `"<n>px"` coordinate unit: CSS reference pixels, also the
|
|
134
|
+
* density ts-pptx assumes when reading an image header's pixel dimensions. */
|
|
135
|
+
const DEFAULT_PX_PER_INCH = 96;
|
|
136
|
+
function inchesToEmu(inches) {
|
|
137
|
+
assertFiniteNumber(inches, "inches");
|
|
138
|
+
return Math.round(inches * EMU_PER_INCH);
|
|
139
|
+
}
|
|
140
|
+
function pointsToEmu(points) {
|
|
141
|
+
assertFiniteNumber(points, "points");
|
|
142
|
+
return Math.round(points * EMU_PER_POINT);
|
|
143
|
+
}
|
|
144
|
+
function pixelsToEmu(pixels, dpi) {
|
|
145
|
+
assertFiniteNumber(pixels, "pixels");
|
|
146
|
+
assertPositiveFiniteNumber(dpi, "dpi");
|
|
147
|
+
return inchesToEmu(pixels / dpi);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Resolve a percentage of an axis length to EMU.
|
|
151
|
+
* @param percent - percentage value (e.g. `50` for 50%)
|
|
152
|
+
* @param axisEmu - the axis length in EMU (slide width for x/w, height for y/h)
|
|
153
|
+
*/
|
|
154
|
+
function percentToEmu(percent, axisEmu) {
|
|
155
|
+
assertFiniteNumber(percent, "percent");
|
|
156
|
+
assertFiniteNumber(axisEmu, "axisEmu");
|
|
157
|
+
return Math.round(percent / 100 * axisEmu);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The single user-coordinate → EMU boundary. Convert each user-supplied coordinate exactly once.
|
|
161
|
+
*
|
|
162
|
+
* Accepts (see {@link Coord}):
|
|
163
|
+
* - a bare `number` → **always inches** (the documented unit); no magnitude guessing
|
|
164
|
+
* - `"<n>%"` → percentage of `axisEmu`
|
|
165
|
+
* - `"<n>in"` / `"<n>pt"` / `"<n>px"` / `"<n>emu"` → explicit units (the escape hatch for non-inch
|
|
166
|
+
* values). `px` is resolved at {@link DEFAULT_PX_PER_INCH} (96), for authoring against a known
|
|
167
|
+
* web/source canvas size.
|
|
168
|
+
*
|
|
169
|
+
* Throws on non-finite or unparseable input rather than silently emitting a degenerate 0-size.
|
|
170
|
+
* @param value - user coordinate
|
|
171
|
+
* @param axisEmu - axis length in EMU, used only to resolve percentages
|
|
172
|
+
*/
|
|
173
|
+
function coordToEmu(value, axisEmu) {
|
|
174
|
+
if (typeof value === "number") {
|
|
175
|
+
assertFiniteNumber(value, "coordinate");
|
|
176
|
+
if (Math.abs(value) > IMPLAUSIBLE_INCHES) warn("coord/bare-number-is-inches", `coordinate ${value} interpreted as ${value} inches. A bare number is always inches; if you meant EMU, pass it as a string like "${Math.round(value)}emu".`);
|
|
177
|
+
return inchesToEmu(value);
|
|
178
|
+
}
|
|
179
|
+
const match = /^\s*(-?\d*\.?\d+)\s*(%|in|pt|px|emu)\s*$/.exec(value);
|
|
180
|
+
if (!match) throw new InvalidOptionError("coord/invalid-format", `Invalid coordinate "${value}". Expected a number (inches) or a string like "50%", "5in", "72pt", "96px", or "914400emu".`);
|
|
181
|
+
const n = Number(match[1]);
|
|
182
|
+
switch (match[2]) {
|
|
183
|
+
case "%": return percentToEmu(n, axisEmu);
|
|
184
|
+
case "in": return inchesToEmu(n);
|
|
185
|
+
case "pt": return pointsToEmu(n);
|
|
186
|
+
case "px": return pixelsToEmu(n, 96);
|
|
187
|
+
default:
|
|
188
|
+
assertFiniteNumber(n, "coordinate");
|
|
189
|
+
return Math.round(n);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function emuToInches(emu) {
|
|
193
|
+
assertFiniteNumber(emu, "emu");
|
|
194
|
+
return emu / EMU_PER_INCH;
|
|
195
|
+
}
|
|
196
|
+
function emuToPoints(emu) {
|
|
197
|
+
assertFiniteNumber(emu, "emu");
|
|
198
|
+
return emu / EMU_PER_POINT;
|
|
199
|
+
}
|
|
200
|
+
function emuToPixels(emu, dpi) {
|
|
201
|
+
assertFiniteNumber(emu, "emu");
|
|
202
|
+
assertPositiveFiniteNumber(dpi, "dpi");
|
|
203
|
+
return Math.round(emuToInches(emu) * dpi);
|
|
204
|
+
}
|
|
205
|
+
function standardLayout(layout, name, widthIn, heightIn) {
|
|
206
|
+
return Object.freeze({
|
|
207
|
+
layout,
|
|
208
|
+
name,
|
|
209
|
+
widthIn,
|
|
210
|
+
heightIn,
|
|
211
|
+
widthEmu: inchesToEmu(widthIn),
|
|
212
|
+
heightEmu: inchesToEmu(heightIn)
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const STANDARD_LAYOUTS = Object.freeze({
|
|
216
|
+
LAYOUT_4x3: standardLayout("LAYOUT_4x3", "screen4x3", 10, 7.5),
|
|
217
|
+
LAYOUT_16x9: standardLayout("LAYOUT_16x9", "screen16x9", 10, 5.625),
|
|
218
|
+
LAYOUT_16x10: standardLayout("LAYOUT_16x10", "screen16x10", 10, 6.25),
|
|
219
|
+
LAYOUT_WIDE: standardLayout("LAYOUT_WIDE", "custom", 40 / 3, 7.5)
|
|
220
|
+
});
|
|
221
|
+
function assertFiniteNumber(value, name) {
|
|
222
|
+
if (!Number.isFinite(value)) throw new InvalidOptionError("coord/non-finite", `${name} must be a finite number`);
|
|
223
|
+
}
|
|
224
|
+
function assertPositiveFiniteNumber(value, name) {
|
|
225
|
+
assertFiniteNumber(value, name);
|
|
226
|
+
if (value <= 0) throw new InvalidOptionError("coord/not-positive", `${name} must be greater than 0`);
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
229
|
+
export { warnOnce as S, pointsToEmu as _, FIXED_PCT_PER_PERCENT as a, setDiagnosticHandler as b, POINTS_PER_INCH as c, emuToInches as d, emuToPixels as f, pixelsToEmu as g, percentToEmu as h, EMU_PER_POINT as i, STANDARD_LAYOUTS as l, inchesToEmu as m, DEFAULT_PX_PER_INCH as n, HUNDREDTHS_PER_POINT as o, emuToPoints as p, EMU_PER_INCH as r, PERCENT_SCALE as s, ANGLE_UNITS_PER_DEGREE as t, coordToEmu as u, ptToHundredths as v, warn as x, resetDiagnosticState as y };
|
|
230
|
+
|
|
231
|
+
//# sourceMappingURL=units-1kRzYShk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"units-1kRzYShk.js","names":[],"sources":["../src/diagnostics.ts","../src/units.ts"],"sourcesContent":["/**\n * Central sink for library diagnostics.\n *\n * Every user-facing warning is routed through {@link warn} / {@link warnOnce} rather than calling\n * `console.warn` directly, so there is one place to apply a consistent prefix and one place a\n * consumer can take over — see {@link setDiagnosticHandler}. This module has no *runtime* imports\n * so it can be used from anywhere without risking an import cycle; `codes.ts` is types only and is\n * erased at compile time, so it does not cost that property.\n *\n * **A diagnostic's `code` is API; its `message` is not.** The code is a stable identifier a\n * consumer may branch on (`if (d.code === 'chart/non-finite-value')`); the wording behind it is\n * free to improve in any release. The vocabulary lives in `codes.ts` and is shared with the thrown\n * surface (`errors.ts`), so a condition that can both warn and throw reads the same either way.\n */\n\nimport type { DiagnosticCode } from './codes.js'\n\nexport type { DiagnosticCode }\n\n/** One diagnostic emitted by the library. */\nexport interface Diagnostic {\n\t/** Stable condition identifier — see {@link DiagnosticCode}. Branch on this, not on the text. */\n\treadonly code: DiagnosticCode\n\t/** Human-readable explanation. Free to change in any release; do not parse it. */\n\treadonly message: string\n\t/**\n\t * Structured context for the condition, when a site has any to give. No site populates it\n\t * today; it exists so one can start to without a breaking signature change.\n\t */\n\treadonly detail?: Readonly<Record<string, unknown>>\n}\n\n/** Receives every {@link Diagnostic} the library emits. See {@link setDiagnosticHandler}. */\nexport type DiagnosticHandler = (diagnostic: Diagnostic) => void\n\n/** Prefix stamped on every warning so consumers can attribute console noise to this library. */\nconst WARN_PREFIX = 'ts-pptx'\n\n/** The default handler: one `console.warn` line per diagnostic, prefixed. */\nconst consoleHandler: DiagnosticHandler = (diagnostic) => {\n\tconsole.warn(`${WARN_PREFIX}: ${diagnostic.message}`)\n}\n\nlet handler: DiagnosticHandler = consoleHandler\n\n/**\n * Route every library diagnostic to `handler`, or pass `null` to restore the default\n * (one prefixed `console.warn` per diagnostic).\n *\n * This is process-global rather than per-presentation, deliberately: the emitting code is a tree\n * of free functions in `gen/**` with no presentation in scope, and threading a handler through\n * every signature would be a far larger and worse change than the problem warrants. The practical\n * consequence is that a process building several decks concurrently cannot attribute a diagnostic\n * to one of them; if that matters, correlate on `code` or set the handler around each build.\n *\n * A throwing handler propagates out of whatever library call emitted the diagnostic, which is the\n * supported way to make a specific condition fatal:\n *\n * ```ts\n * setDiagnosticHandler((d) => {\n * if (d.code === 'coord/bare-number-is-inches') throw new Error(d.message)\n * })\n * ```\n * @param next - the receiver, or `null` to restore the console default\n */\nexport function setDiagnosticHandler(next: DiagnosticHandler | null): void {\n\thandler = next ?? consoleHandler\n}\n\n/**\n * Emit a library diagnostic.\n * @param code - the stable condition identifier ({@link DiagnosticCode})\n * @param message - explanation, without a `ts-pptx:` prefix (the default handler adds one)\n * @param detail - optional structured context\n */\nexport function warn(code: DiagnosticCode, message: string, detail?: Readonly<Record<string, unknown>>): void {\n\thandler(detail === undefined ? { code, message } : { code, message, detail })\n}\n\n// Track diagnostics already emitted so a recurring condition (e.g. the same out-of-range fontSize\n// on every cell of a table) is reported once instead of flooding the handler. Keyed on code AND\n// message, so a *different* offending value under the same code still reports.\nconst seen = new Set<string>()\n\n/**\n * Emit a library diagnostic at most once per distinct code+message.\n *\n * \"Once\" is **process-global**, the same scope {@link setDiagnosticHandler} has and for the\n * same reason: the emitting code is a tree of free functions in `gen/**` with no presentation\n * in scope. The consequence is different, though, and worth stating on its own — a process that\n * builds several decks does not get a second report of a condition an earlier deck already\n * tripped, so the second deck's diagnostics are incomplete rather than merely unattributed.\n * {@link resetDiagnosticState} is how a host that cares gets each build a clean slate.\n *\n * @param code - the stable condition identifier ({@link DiagnosticCode})\n * @param message - explanation (see {@link warn})\n * @param detail - optional structured context\n */\nexport function warnOnce(code: DiagnosticCode, message: string, detail?: Readonly<Record<string, unknown>>): void {\n\tconst key = `${code}\\0${message}`\n\tif (seen.has(key)) return\n\tseen.add(key)\n\twarn(code, message, detail)\n}\n\n/**\n * Clear the {@link warnOnce} dedupe set, so a condition already reported reports again.\n *\n * Call it between builds in a host that builds more than one deck per process and wants each\n * build's diagnostics complete. Without it, deck two is silent about anything deck one already\n * warned for, which reads as \"no problems found\" rather than as \"already mentioned\".\n *\n * It also bounds the set. Most `warnOnce` messages interpolate the offending value, so a server\n * building decks from user input accumulates one entry per distinct bad value with no way to\n * release them.\n *\n * This does not touch the handler — {@link setDiagnosticHandler} owns that, and the two are\n * reset independently on purpose: a host usually installs its handler once and wants it to\n * survive.\n */\nexport function resetDiagnosticState(): void {\n\tseen.clear()\n}\n","import { warn } from './diagnostics.js'\nimport { InvalidOptionError } from './errors.js'\n/**\n * Public unit conversion helpers and standard PowerPoint slide-layout constants.\n */\n\nexport const EMU_PER_INCH = 914400\nexport const EMU_PER_POINT = 12700\nexport const POINTS_PER_INCH = 72\n\n/**\n * DrawingML angle unit. `ST_Angle` (`rot`, shadow `dir`, gradient `ang`, …) is measured in\n * sixtieths-of-a-thousandth of a degree, i.e. 60000 units per degree. Multiply a value in\n * degrees by this to get the OOXML integer.\n */\nexport const ANGLE_UNITS_PER_DEGREE = 60000\n\n/**\n * DrawingML fixed-point percentage scale. `ST_Percentage` / `ST_PositiveFixedPercentage` and\n * related types (`<a:alpha>`, `<a:spcPct>`, shape adjustment guides, `<p:tav tm>`, …) encode\n * 100% as the integer 100000. Multiply a 0-1 fraction by this to get the OOXML value.\n */\nexport const PERCENT_SCALE = 100000\n\n/**\n * Scale for a percentage supplied as 0-100 (rather than a 0-1 fraction) into the same\n * fixed-point percentage integer as {@link PERCENT_SCALE} (1% = 1000 units, i.e. thousandths\n * of a percent). Use for inputs documented as percents: transparency/alpha, image crop insets,\n * gradient stops, bullet size, connector adjust, etc.\n */\nexport const FIXED_PCT_PER_PERCENT = PERCENT_SCALE / 100\n\n/**\n * DrawingML text measures font size (`sz`), character spacing (`spc`) and point line/paragraph\n * spacing (`<a:spcPts val>`) in hundredths of a point. Multiply a value in points by this to get\n * the OOXML integer.\n */\nexport const HUNDREDTHS_PER_POINT = 100\n\n/**\n * Convert a value in points to hundredths of a point (rounded), the integer unit DrawingML uses\n * for `sz`, `spc`, and `<a:spcPts val>`. See {@link HUNDREDTHS_PER_POINT}.\n */\nexport function ptToHundredths(pt: number): number {\n\tassertFiniteNumber(pt, 'points')\n\treturn Math.round(pt * HUNDREDTHS_PER_POINT)\n}\n\n/**\n * English Metric Units — the integer unit OOXML serializes geometry in (914400 per inch).\n *\n * Branded so a value that has already been resolved to EMU cannot be silently fed back into a\n * unit converter: {@link coordToEmu} only accepts a user `Coord`, so passing an `Emu` into it is\n * a compile-time error. This replaces the old runtime \"a number ≥ 100 must already be EMU\"\n * magnitude guess, which silently mis-rendered values near the threshold.\n */\nexport type Emu = number & { readonly __unit: 'emu' }\n\n/** A bare number larger than this (in inches) is almost certainly a mistake — likely a raw EMU\n * value passed where inches are expected. We interpret it as inches (the documented contract) but\n * warn, pointing at the explicit `\"<n>emu\"` form. ~1000in is far beyond any real slide. */\nconst IMPLAUSIBLE_INCHES = 1000\n\n/** Default pixel density for the `\"<n>px\"` coordinate unit: CSS reference pixels, also the\n * density ts-pptx assumes when reading an image header's pixel dimensions. */\nexport const DEFAULT_PX_PER_INCH = 96\n\nexport type StandardLayoutName = 'LAYOUT_4x3' | 'LAYOUT_16x9' | 'LAYOUT_16x10' | 'LAYOUT_WIDE'\n\nexport interface StandardLayout {\n\t/** ts-pptx layout key used with `pptx.layout`. */\n\treadonly layout: StandardLayoutName\n\t/** PresentationML slide-size preset name, or `custom` for PowerPoint widescreen. */\n\treadonly name: string\n\t/** Slide width in inches — inches is ts-pptx's default coordinate unit, so this is the value to use for `addText`/`addShape` math. */\n\treadonly widthIn: number\n\t/** Slide height in inches. */\n\treadonly heightIn: number\n\t/** Slide width in English Metric Units. */\n\treadonly widthEmu: number\n\t/** Slide height in English Metric Units. */\n\treadonly heightEmu: number\n}\n\nexport function inchesToEmu(inches: number): Emu {\n\tassertFiniteNumber(inches, 'inches')\n\treturn Math.round(inches * EMU_PER_INCH) as Emu\n}\n\nexport function pointsToEmu(points: number): Emu {\n\tassertFiniteNumber(points, 'points')\n\treturn Math.round(points * EMU_PER_POINT) as Emu\n}\n\nexport function pixelsToEmu(pixels: number, dpi: number): Emu {\n\tassertFiniteNumber(pixels, 'pixels')\n\tassertPositiveFiniteNumber(dpi, 'dpi')\n\treturn inchesToEmu(pixels / dpi)\n}\n\n/**\n * Resolve a percentage of an axis length to EMU.\n * @param percent - percentage value (e.g. `50` for 50%)\n * @param axisEmu - the axis length in EMU (slide width for x/w, height for y/h)\n */\nexport function percentToEmu(percent: number, axisEmu: number): Emu {\n\tassertFiniteNumber(percent, 'percent')\n\tassertFiniteNumber(axisEmu, 'axisEmu')\n\treturn Math.round((percent / 100) * axisEmu) as Emu\n}\n\n/**\n * The single user-coordinate → EMU boundary. Convert each user-supplied coordinate exactly once.\n *\n * Accepts (see {@link Coord}):\n * - a bare `number` → **always inches** (the documented unit); no magnitude guessing\n * - `\"<n>%\"` → percentage of `axisEmu`\n * - `\"<n>in\"` / `\"<n>pt\"` / `\"<n>px\"` / `\"<n>emu\"` → explicit units (the escape hatch for non-inch\n * values). `px` is resolved at {@link DEFAULT_PX_PER_INCH} (96), for authoring against a known\n * web/source canvas size.\n *\n * Throws on non-finite or unparseable input rather than silently emitting a degenerate 0-size.\n * @param value - user coordinate\n * @param axisEmu - axis length in EMU, used only to resolve percentages\n */\nexport function coordToEmu(value: number | string, axisEmu: number): Emu {\n\tif (typeof value === 'number') {\n\t\tassertFiniteNumber(value, 'coordinate')\n\t\tif (Math.abs(value) > IMPLAUSIBLE_INCHES) {\n\t\t\twarn(\n\t\t\t\t'coord/bare-number-is-inches',\n\t\t\t\t`coordinate ${value} interpreted as ${value} inches. A bare number is always inches; ` +\n\t\t\t\t\t`if you meant EMU, pass it as a string like \"${Math.round(value)}emu\".`\n\t\t\t)\n\t\t}\n\t\treturn inchesToEmu(value)\n\t}\n\n\tconst match = /^\\s*(-?\\d*\\.?\\d+)\\s*(%|in|pt|px|emu)\\s*$/.exec(value)\n\tif (!match) {\n\t\tthrow new InvalidOptionError(\n\t\t\t'coord/invalid-format',\n\t\t\t`Invalid coordinate \"${value}\". Expected a number (inches) or a string like \"50%\", \"5in\", \"72pt\", \"96px\", or \"914400emu\".`\n\t\t)\n\t}\n\tconst n = Number(match[1])\n\tswitch (match[2]) {\n\t\tcase '%':\n\t\t\treturn percentToEmu(n, axisEmu)\n\t\tcase 'in':\n\t\t\treturn inchesToEmu(n)\n\t\tcase 'pt':\n\t\t\treturn pointsToEmu(n)\n\t\tcase 'px':\n\t\t\treturn pixelsToEmu(n, DEFAULT_PX_PER_INCH)\n\t\tdefault: // 'emu'\n\t\t\tassertFiniteNumber(n, 'coordinate')\n\t\t\treturn Math.round(n) as Emu\n\t}\n}\n\nexport function emuToInches(emu: number): number {\n\tassertFiniteNumber(emu, 'emu')\n\treturn emu / EMU_PER_INCH\n}\n\nexport function emuToPoints(emu: number): number {\n\tassertFiniteNumber(emu, 'emu')\n\treturn emu / EMU_PER_POINT\n}\n\nexport function emuToPixels(emu: number, dpi: number): number {\n\tassertFiniteNumber(emu, 'emu')\n\tassertPositiveFiniteNumber(dpi, 'dpi')\n\treturn Math.round(emuToInches(emu) * dpi)\n}\n\nfunction standardLayout(layout: StandardLayoutName, name: string, widthIn: number, heightIn: number): StandardLayout {\n\treturn Object.freeze({\n\t\tlayout,\n\t\tname,\n\t\twidthIn,\n\t\theightIn,\n\t\twidthEmu: inchesToEmu(widthIn),\n\t\theightEmu: inchesToEmu(heightIn),\n\t})\n}\n\nexport const STANDARD_LAYOUTS: Readonly<Record<StandardLayoutName, StandardLayout>> = Object.freeze({\n\tLAYOUT_4x3: standardLayout('LAYOUT_4x3', 'screen4x3', 10, 7.5),\n\tLAYOUT_16x9: standardLayout('LAYOUT_16x9', 'screen16x9', 10, 5.625),\n\tLAYOUT_16x10: standardLayout('LAYOUT_16x10', 'screen16x10', 10, 6.25),\n\tLAYOUT_WIDE: standardLayout('LAYOUT_WIDE', 'custom', 40 / 3, 7.5),\n})\n\nfunction assertFiniteNumber(value: number, name: string): void {\n\tif (!Number.isFinite(value)) throw new InvalidOptionError('coord/non-finite', `${name} must be a finite number`)\n}\n\nfunction assertPositiveFiniteNumber(value: number, name: string): void {\n\tassertFiniteNumber(value, name)\n\tif (value <= 0) throw new InvalidOptionError('coord/not-positive', `${name} must be greater than 0`)\n}\n"],"mappings":"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"}
|