@pptx-studio/cli 0.1.0 → 0.3.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/CHANGELOG.md +149 -0
- package/README.md +95 -11
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +56 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{main-DLx2onii.js → main-3sNR_Xlp.js} +262 -99
- package/dist/main-3sNR_Xlp.js.map +1 -0
- package/package.json +9 -9
- package/dist/main-DLx2onii.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-3sNR_Xlp.js","names":[],"sources":["../src/bisect.ts","../src/inspect.ts","../src/render/errors.ts","../src/render/sfnt.ts","../src/render/faces.ts","../src/render/measure.ts","../src/render/render.ts","../src/roundtrip.ts","../src/validate.ts","../src/main.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { readZip } from '@pptx-studio/opc';\nimport { firstDifference } from '@pptx-studio/xml';\nimport { validatePackage } from '@pptx-studio/validate';\nimport {\n bisectPackages,\n describeChange,\n flattenChanges,\n roundTripPackage,\n summarizeBisect,\n type BisectResult,\n type Change,\n type Oracle,\n type Verdict,\n} from '@pptx-studio/writer';\n\n/**\n * `pptx-studio bisect deck.pptx`\n *\n * Find the smallest change that makes a package fail.\n *\n * ## What it is for\n *\n * It is the debugger for this project, and the plan says so in as many words.\n * `validate` answers \"does this break one of the twenty-nine rules\"; `roundtrip`\n * answers \"did we change anything\"; neither answers the question you actually\n * have at two in the morning, which is *which* of the four hundred things that\n * changed is the one PowerPoint objects to.\n *\n * ## Two ways to call it\n *\n * With one deck, the broken package is **our own export of it**. That is the\n * workflow this exists for: we read a file, wrote it back, and PowerPoint now\n * wants to repair it - so the delta to search is exactly what the writer did.\n *\n * With two, they are the original and the broken package, in that order. Use\n * this when the broken one came from somewhere else: an edit made through the\n * library, a hand-mangled fixture, a file a user sent in.\n *\n * ## The oracles\n *\n * `--oracle validate` (the default) asks the twenty-nine rules. It needs no\n * PowerPoint, runs in milliseconds, and is what the tests use - but it can only\n * find failures we already know how to describe.\n *\n * `--oracle powerpoint` asks the real thing, on Windows, over COM. This is the\n * one that matters, because the interesting failures are the ones no rule\n * covers. It opens each candidate with `OpenAndRepair` switched **off**, which\n * is the only way to see a repair at all: PowerPoint's automation interface\n * repairs silently by default and reports success.\n *\n * `--oracle command --command \"...\"` runs anything else. `{}` in the command is\n * replaced with the path to the candidate package; a non-zero exit means the\n * candidate fails.\n */\n\nexport type OracleName = 'validate' | 'powerpoint' | 'command';\n\nexport interface BisectOptions {\n readonly oracle: OracleName;\n /** The shell command for `--oracle command`. `{}` becomes the candidate path. */\n readonly command: string | null;\n readonly maxRuns: number;\n /** Per-run ceiling in milliseconds, for the oracles that spawn something. */\n readonly timeout: number;\n /** Save the smallest failing package here. */\n readonly write: string | null;\n readonly json: boolean;\n readonly quiet: boolean;\n readonly out: string | null;\n /** Print a line per oracle run. Off by default; a bisection is not quick. */\n readonly progress: boolean;\n}\n\nexport const BISECT_DEFAULTS: BisectOptions = {\n oracle: 'validate',\n command: null,\n maxRuns: 2000,\n timeout: 120_000,\n write: null,\n json: false,\n quiet: false,\n out: null,\n progress: false,\n};\n\n/** Where `powerpoint-oracle.ps1` lives, from `src/` and from `dist/` alike. */\nexport function oracleScriptPath(): string {\n return fileURLToPath(new URL('../scripts/powerpoint-oracle.ps1', import.meta.url));\n}\n\n/**\n * The twenty-nine rules, asked of one candidate.\n *\n * No baseline is supplied and none could be: a candidate is a package that\n * never existed until this run, and it has no history. That makes every fatal\n * finding count as ours, which is the safe direction here for the same reason\n * it is in `validate` - the question is \"is this package broken\", not \"who\n * broke it\".\n */\nexport function validateOracle(): Oracle {\n return (bytes) => {\n try {\n return validatePackage({ bytes }).ok ? 'passes' : 'fails';\n } catch {\n // A candidate that will not open at all is a failure of a different kind,\n // and one this reducer must not chase: it means the splice produced\n // something that is not a package, which is a bug here rather than a\n // finding about the deck.\n return 'unresolved';\n }\n };\n}\n\ninterface SpawnOracleOptions {\n readonly timeout: number;\n readonly directory: string;\n readonly onSpawn?: (verdict: Verdict, detail: string) => void;\n}\n\n/** Write the candidate somewhere, run something over it, read the exit code. */\nfunction spawningOracle(\n run: (path: string) => { status: number | null; signal: string | null; stderr: string },\n options: SpawnOracleOptions,\n): Oracle {\n const path = join(options.directory, 'candidate.pptx');\n return (bytes) => {\n writeFileSync(path, bytes);\n const result = run(path);\n if (result.signal !== null || result.status === null) {\n // Killed, or timed out. Neither is an answer about the package.\n options.onSpawn?.('unresolved', result.signal ?? 'no exit status');\n return 'unresolved';\n }\n const verdict: Verdict =\n result.status === 0 ? 'passes' : result.status === 1 ? 'fails' : 'unresolved';\n options.onSpawn?.(verdict, 'exit ' + String(result.status));\n return verdict;\n };\n}\n\nexport function powerPointOracle(options: SpawnOracleOptions): Oracle {\n const script = oracleScriptPath();\n return spawningOracle((path) => {\n const result = spawnSync(\n 'powershell.exe',\n ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', script, '-File', path],\n { timeout: options.timeout, encoding: 'utf8', windowsHide: true },\n );\n return {\n status: result.status,\n signal: result.signal,\n stderr: result.stderr ?? '',\n };\n }, options);\n}\n\nexport function commandOracle(command: string, options: SpawnOracleOptions): Oracle {\n return spawningOracle((path) => {\n const filled = command.includes('{}') ? command.replaceAll('{}', path) : command + ' ' + path;\n const result = spawnSync(filled, {\n shell: true,\n timeout: options.timeout,\n encoding: 'utf8',\n windowsHide: true,\n });\n // A shell that could not start the command reports 127, and a command\n // that does not exist is not a broken package. Only 0 and 1 are answers.\n return { status: result.status, signal: result.signal, stderr: result.stderr ?? '' };\n }, options);\n}\n\n/** Shut down a PowerPoint this run started, so a bisection leaves nothing behind. */\nexport function quitPowerPoint(timeout: number): void {\n spawnSync(\n 'powershell.exe',\n ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', oracleScriptPath(), '-QuitOnly'],\n { timeout, encoding: 'utf8', windowsHide: true },\n );\n}\n\nexport interface BisectStats {\n readonly original: string;\n readonly broken: string;\n readonly bytesOriginal: number;\n readonly bytesBroken: number;\n readonly entriesOriginal: number;\n readonly entriesBroken: number;\n readonly oracle: OracleName;\n}\n\n/**\n * A change's two sides, short enough to read and showing where they part.\n *\n * Truncating both from the front is the obvious thing and it is useless: two\n * versions of a 4 kB element that differ at character 3 000 come out as the\n * same sixty-eight characters twice, which reads as a bug in the bisector. So\n * the window is centred on the first character where they actually differ.\n */\nfunction sides(change: Change, width = 66): string[] {\n const flatten = (text: string): string => text.replaceAll('\\r', '').replaceAll('\\n', '⏎');\n const was = change.was === null ? null : flatten(change.was);\n const text = change.text === null ? null : flatten(change.text);\n\n let from = 0;\n if (was !== null && text !== null && (was.length > width || text.length > width)) {\n const at = firstDifference(was, text);\n if (at > width / 2) from = Math.floor(at - width / 2);\n }\n\n const show = (value: string | null, mark: string): string => {\n if (value === null) return ' ' + mark + ' (absent)';\n if (value === '') return ' ' + mark + ' (nothing)';\n const head = from > 0 ? '…' : '';\n const body = value.slice(from, from + width);\n const tail = from + width < value.length ? '…' : '';\n return ' ' + mark + ' ' + head + body + tail;\n };\n return [show(was, '-'), show(text, '+')];\n}\n\n/**\n * Render a result.\n *\n * Exported for the same reason `formatRoundTrip` is: the branches worth reading\n * are the ones a green corpus cannot produce, and they need a test of their own.\n */\nexport function formatBisect(stats: BisectStats, result: BisectResult, quiet: boolean): string {\n const lines: string[] = [];\n\n if (!quiet) {\n lines.push(\n 'bisect ' + stats.original,\n ' vs. ' + stats.broken,\n '',\n ' original ' +\n String(stats.bytesOriginal) +\n ' bytes, ' +\n String(stats.entriesOriginal) +\n ' entries',\n ' broken ' +\n String(stats.bytesBroken) +\n ' bytes, ' +\n String(stats.entriesBroken) +\n ' entries',\n ' delta ' +\n String(flattenChanges(result.changes).length) +\n ' change(s) in ' +\n String(result.changes.length) +\n ' entry(s)',\n ' oracle ' +\n stats.oracle +\n ', ' +\n String(result.runs) +\n ' run(s)' +\n (result.cached > 0 ? ', ' + String(result.cached) + ' from cache' : '') +\n (result.unresolved > 0 ? ', ' + String(result.unresolved) + ' unresolved' : ''),\n '',\n );\n }\n\n switch (result.outcome) {\n case 'identical':\n lines.push(' the two packages hold the same entries, byte for byte');\n break;\n case 'broken-passes':\n lines.push(\n ' the second package passes the oracle, so there is nothing to look for',\n ' (' +\n String(flattenChanges(result.changes).length) +\n ' change(s) between them, none fatal)',\n );\n break;\n case 'original-fails':\n lines.push(\n ' the *original* fails the oracle, so the cause is not in the difference',\n ' nothing was narrowed down; look at the original package first',\n );\n break;\n case 'localized':\n lines.push(' ' + summarizeBisect(result), '');\n for (const change of result.minimal) {\n lines.push(' ' + describeChange(change), ...sides(change), '');\n }\n break;\n }\n\n if (result.exhausted) {\n lines.push(\n '',\n ' stopped at the ceiling of ' + String(result.runs) + ' oracle run(s).',\n ' the answer above still fails, but it is not minimal - raise --max-runs.',\n );\n }\n if (result.truncated) {\n lines.push(\n '',\n ' the delta was too large to decompose completely, so some changes are',\n ' whole entries rather than elements - raise --max-changes.',\n );\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nexport interface BisectFileResult {\n readonly result: BisectResult;\n readonly output: string;\n readonly exitCode: number;\n}\n\nexport function bisectFiles(\n originalPath: string,\n brokenPath: string | null,\n options: BisectOptions = BISECT_DEFAULTS,\n note: (text: string) => void = () => {},\n): BisectFileResult {\n const original = new Uint8Array(readFileSync(originalPath));\n // One argument means \"bisect what our own writer did to this deck\", which is\n // the case this command was built for.\n const broken =\n brokenPath === null\n ? roundTripPackage(original).exported.bytes\n : new Uint8Array(readFileSync(brokenPath));\n\n const directory = mkdtempSync(join(tmpdir(), 'pptx-bisect-'));\n try {\n const spawnOptions: SpawnOracleOptions = { timeout: options.timeout, directory };\n const oracle: Oracle =\n options.oracle === 'validate'\n ? validateOracle()\n : options.oracle === 'powerpoint'\n ? powerPointOracle(spawnOptions)\n : commandOracle(options.command ?? '', spawnOptions);\n\n const result = bisectPackages(original, broken, {\n oracle,\n maxRuns: options.maxRuns,\n ...(options.progress\n ? {\n onRun: (run) => {\n note(' run ' + String(run.run).padStart(4) + ' ' + run.label + '\\n');\n },\n }\n : {}),\n });\n\n const stats: BisectStats = {\n original: originalPath,\n broken: brokenPath ?? '(our own export of it)',\n bytesOriginal: original.length,\n bytesBroken: broken.length,\n entriesOriginal: readZip(original).entries.length,\n entriesBroken: readZip(broken).entries.length,\n oracle: options.oracle,\n };\n\n const output = options.json\n ? JSON.stringify(\n {\n original: originalPath,\n broken: stats.broken,\n oracle: options.oracle,\n outcome: result.outcome,\n runs: result.runs,\n cached: result.cached,\n unresolved: result.unresolved,\n exhausted: result.exhausted,\n truncated: result.truncated,\n delta: flattenChanges(result.changes).length,\n minimal: result.minimal.map((change) => ({\n entry: change.entry,\n kind: change.kind,\n where: change.where,\n was: change.was,\n text: change.text,\n })),\n },\n null,\n 2,\n ) + '\\n'\n : formatBisect(stats, result, options.quiet);\n\n if (options.write !== null) writeFileSync(options.write, result.bytes);\n\n return {\n result,\n output,\n // Non-zero whenever the deck is not clean, which is the three outcomes\n // that are not \"nothing to report\" - the same shape `validate` and\n // `roundtrip` use, so the three verbs can be chained in a script.\n exitCode: result.outcome === 'localized' || result.outcome === 'original-fails' ? 1 : 0,\n };\n } finally {\n rmSync(directory, { recursive: true, force: true });\n if (options.oracle === 'powerpoint') quitPowerPoint(options.timeout);\n }\n}\n\nexport function runBisect(\n originalPath: string,\n brokenPath: string | null,\n options: BisectOptions,\n write: (text: string) => void,\n): number {\n const result = bisectFiles(originalPath, brokenPath, options, write);\n if (options.out === null) write(result.output);\n else writeFileSync(options.out, result.output);\n return result.exitCode;\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { censusPackage, formatCensus, type PackageCensus } from '@pptx-studio/census';\n\n/**\n * `pptx-studio inspect deck.pptx`\n *\n * Everything this command knows about `.pptx` lives in `@pptx-studio/census`,\n * which is a browser package with no Node in it. That split is deliberate and\n * it is the reason the census exists as a package at all: the browser explorer\n * in `apps/studio` computes exactly the same object in a Web Worker, so a\n * question answered here and a question answered in a tab cannot drift.\n *\n * What is left for this file is the two things a browser cannot do - read a\n * path off the filesystem, and write to a stream - plus argument handling.\n */\n\nexport interface InspectOptions {\n readonly json: boolean;\n readonly parts: boolean;\n readonly namespaces: boolean;\n readonly top: number;\n /** Write to this path instead of stdout. */\n readonly out: string | null;\n}\n\nexport const INSPECT_DEFAULTS: InspectOptions = {\n json: false,\n parts: false,\n namespaces: false,\n top: 15,\n out: null,\n};\n\nexport interface InspectResult {\n readonly census: PackageCensus;\n readonly output: string;\n /**\n * Process exit code.\n *\n * `1` when the census found something it classes as an error, `0` otherwise -\n * a warning or a note never fails the command. That distinction is what makes\n * `inspect` usable in a script: \"did this deck load, and is anything in it\n * structurally broken\" is a yes/no question, while \"is anything in it\n * unusual\" is not.\n */\n readonly exitCode: number;\n}\n\n/** Run a census over one file and render it. Does no I/O of its own beyond the read. */\nexport function inspectFile(\n path: string,\n options: InspectOptions = INSPECT_DEFAULTS,\n): InspectResult {\n const bytes = new Uint8Array(readFileSync(path));\n const census = censusPackage(bytes);\n\n const output = options.json\n ? JSON.stringify(census, null, 2) + '\\n'\n : formatCensus(census, {\n parts: options.parts,\n namespaces: options.namespaces,\n top: options.top,\n });\n\n const errors = census.problems.filter((problem) => problem.severity === 'error').length;\n return { census, output, exitCode: errors > 0 ? 1 : 0 };\n}\n\n/** Run `inspectFile` and put the result where the options say. */\nexport function runInspect(\n path: string,\n options: InspectOptions,\n write: (text: string) => void,\n): number {\n const result = inspectFile(path, options);\n if (options.out === null) write(result.output);\n else writeFileSync(options.out, result.output);\n return result.exitCode;\n}\n","/**\n * Typed failures for rendering outside a browser.\n *\n * The browser renderer cannot produce any of these: it is handed a measuring\n * canvas and a font stack, and the platform answers. In Node both of those are\n * ours to find, so both are ours to fail at. ADR 0042.\n */\nexport type RenderErrorCode =\n /** Bytes that are not an SFNT font, or a table the reader needs is absent. */\n | 'CLI_FONT_UNREADABLE'\n /** A font directory that was named on the command line and does not exist. */\n | 'CLI_FONT_DIR'\n /** No face on this machine can stand in for a typeface the deck names. */\n | 'CLI_NO_FACE'\n /** A run whose resolved size is not a positive number of hundredths of a point. */\n | 'CLI_FONT_SIZE'\n /** A slide index outside the deck. */\n | 'CLI_NO_SLIDE'\n /** A width that is not a positive whole number of pixels. */\n | 'CLI_WIDTH'\n /** An output path that names no directory, or a directory that is a file. */\n | 'CLI_OUTPUT_PATH';\n\nexport const RENDER_ERROR_CODES: readonly RenderErrorCode[] = [\n 'CLI_FONT_UNREADABLE',\n 'CLI_FONT_DIR',\n 'CLI_NO_FACE',\n 'CLI_FONT_SIZE',\n 'CLI_NO_SLIDE',\n 'CLI_WIDTH',\n 'CLI_OUTPUT_PATH',\n];\n\nexport class RenderError extends Error {\n override readonly name = 'RenderError';\n readonly code: RenderErrorCode;\n /** The font file, deck path or typeface the failure is about. */\n readonly subject: string;\n\n constructor(code: RenderErrorCode, message: string, subject: string) {\n super(message);\n this.code = code;\n this.subject = subject;\n }\n}\n\nexport function isRenderError(error: unknown): error is RenderError {\n return error instanceof RenderError;\n}\n","/**\n * The four tables a measurement needs, read out of a font file.\n *\n * Not a font library: nothing here decodes an outline, and a CFF font is read\n * as happily as a glyf one because advances live in `hmtx` either way. What it\n * answers is the question the browser answers with `measureText`, which is the\n * one thing `render-svg` cannot get in Node. Every reading below was measured\n * against Chromium in experiment T13 rather than taken from the specification.\n * ADR 0042.\n */\n\nimport { RenderError } from './errors.js';\n\nconst OTTO = 0x4f54544f;\nconst TRUE_TYPE = 0x00010000;\nconst TTCF = 0x74746366;\n\n/** `OS/2.fsSelection` bit 7: the typographic metrics are the ones to use. */\nconst USE_TYPO_METRICS = 0x0080;\n\n/**\n * The rasteriser a Chromium reads a face's vertical metrics through.\n *\n * T13 scored `usWin` 30/30 against DirectWrite on fonts built to disagree; T14\n * scored `hhea` 94/94 against FreeType and 248/248 against CoreText on real\n * faces. One reader cannot answer for all three. ADR 0045, ADR 0053.\n */\nexport type FontBackend = 'directwrite' | 'freetype' | 'coretext';\n\n/** FreeType on Linux, CoreText on macOS, DirectWrite elsewhere. ADR 0045, ADR 0053. */\nexport function backendFor(platform: string): FontBackend {\n if (platform === 'linux') return 'freetype';\n if (platform === 'darwin') return 'coretext';\n return 'directwrite';\n}\n\n/** One ascent and descent in font units, the descent positive below the baseline. */\nexport interface MetricPair {\n readonly ascent: number;\n readonly descent: number;\n}\n\n/** Every pair a browser could report a face box from, each as its table wrote it. */\nexport interface MetricCandidates {\n readonly hhea: MetricPair;\n /** `undefined` on a face with no `OS/2` table long enough to hold version 0. */\n readonly usWin: MetricPair | undefined;\n readonly sTypo: MetricPair | undefined;\n /** `OS/2.fsSelection` bit 7, USE_TYPO_METRICS. */\n readonly useTypoMetrics: boolean;\n}\n\nexport interface FaceMetrics {\n /** `head.unitsPerEm`, the denominator of every number here. */\n readonly unitsPerEm: number;\n /** Above the baseline, in font units. */\n readonly ascent: number;\n /** Below the baseline, in font units, positive. */\n readonly descent: number;\n /** Which table `ascent` and `descent` came out of, for the diagnostics. */\n readonly source: 'hhea' | 'usWin' | 'sTypo';\n /** The rasteriser `source` was chosen for, which also fixes how the box rounds. */\n readonly backend: FontBackend;\n /** The `BASE` `ideo` coordinate under `DFLT`, in font units below the baseline. */\n readonly ideographic: number | undefined;\n /** The pairs `ascent` and `descent` were chosen from, so a rival reading is scorable. */\n readonly candidates: MetricCandidates;\n}\n\nexport interface Face {\n /** `name` ID 1, which is what PowerPoint matches a typeface on. */\n readonly family: string;\n /** `name` ID 2: `Regular`, `Bold`, `Italic`, `Bold Italic`, or a style name. */\n readonly subfamily: string;\n /** `name` ID 16, present when the family splits into more than four styles. */\n readonly typographicFamily: string | undefined;\n readonly metrics: FaceMetrics;\n readonly bold: boolean;\n readonly italic: boolean;\n /** Code point to advance, in font units. */\n advanceOf(codePoint: number): number | undefined;\n /** The adjustment between two code points, in font units. Usually zero. */\n kernBetween(left: number, right: number): number;\n}\n\ninterface Reader {\n readonly bytes: Uint8Array;\n readonly view: DataView;\n}\n\nfunction readerOf(bytes: Uint8Array): Reader {\n return { bytes, view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength) };\n}\n\nfunction u8(r: Reader, at: number): number {\n return r.view.getUint8(at);\n}\nfunction u16(r: Reader, at: number): number {\n return r.view.getUint16(at);\n}\nfunction i16(r: Reader, at: number): number {\n return r.view.getInt16(at);\n}\nfunction u32(r: Reader, at: number): number {\n return r.view.getUint32(at);\n}\n\nfunction tagAt(r: Reader, at: number): string {\n return String.fromCharCode(u8(r, at), u8(r, at + 1), u8(r, at + 2), u8(r, at + 3));\n}\n\nfunction unreadable(what: string, subject: string): never {\n throw new RenderError('CLI_FONT_UNREADABLE', what, subject);\n}\n\n/* -------------------------------------------------------------------------- */\n/* the table directory */\n/* -------------------------------------------------------------------------- */\n\ntype Tables = ReadonlyMap<string, Uint8Array>;\n\nfunction directoryAt(bytes: Uint8Array, start: number, subject: string): Tables {\n const r = readerOf(bytes);\n if (start + 12 > bytes.length) unreadable('font directory runs past the file', subject);\n const count = u16(r, start + 4);\n const out = new Map<string, Uint8Array>();\n for (let i = 0; i < count; i++) {\n const at = start + 12 + i * 16;\n if (at + 16 > bytes.length) unreadable('table directory runs past the file', subject);\n const tag = tagAt(r, at);\n const offset = u32(r, at + 8);\n const length = u32(r, at + 12);\n // A length that runs past the end is a truncated file, not a fatal one:\n // clamping keeps a readable `name` usable when a trailing table is short.\n if (offset < bytes.length)\n out.set(tag, bytes.subarray(offset, Math.min(offset + length, bytes.length)));\n }\n return out;\n}\n\n/** Every font in the file: one for a plain font, several for a collection. */\nexport function fontsIn(bytes: Uint8Array, subject: string): readonly Tables[] {\n if (bytes.length < 12) unreadable('too short to be a font', subject);\n const r = readerOf(bytes);\n const version = u32(r, 0);\n if (version === TTCF) {\n const count = u32(r, 8);\n const out: Tables[] = [];\n for (let i = 0; i < count; i++) out.push(directoryAt(bytes, u32(r, 12 + i * 4), subject));\n return out;\n }\n if (version !== TRUE_TYPE && version !== OTTO) {\n unreadable(`0x${version.toString(16).padStart(8, '0')} is not an SFNT signature`, subject);\n }\n return [directoryAt(bytes, 0, subject)];\n}\n\nfunction required(tables: Tables, tag: string, subject: string): Uint8Array {\n const table = tables.get(tag);\n if (table === undefined) unreadable(`no ${tag} table`, subject);\n return table;\n}\n\n/* -------------------------------------------------------------------------- */\n/* name */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The names a face is known by, decoded from the Windows platform records.\n *\n * Platform 3 encoding 1 is UTF-16BE and is what every font shipped for Windows\n * carries; platform 1 is Mac Roman and is read only where a face has no\n * Windows record at all, which is rare enough to be worth the four lines.\n */\nfunction namesOf(tables: Tables, subject: string): ReadonlyMap<number, string> {\n const table = required(tables, 'name', subject);\n const r = readerOf(table);\n if (table.length < 6) unreadable('name table is truncated', subject);\n const count = u16(r, 2);\n const storage = u16(r, 4);\n const out = new Map<number, string>();\n const seenWindows = new Set<number>();\n for (let i = 0; i < count; i++) {\n const at = 6 + i * 12;\n if (at + 12 > table.length) break;\n const platform = u16(r, at);\n const encoding = u16(r, at + 2);\n const nameId = u16(r, at + 6);\n const length = u16(r, at + 8);\n const offset = storage + u16(r, at + 10);\n if (offset + length > table.length) continue;\n const raw = table.subarray(offset, offset + length);\n if (platform === 3 && (encoding === 1 || encoding === 0)) {\n let text = '';\n for (let j = 0; j + 1 < raw.length; j += 2) {\n text += String.fromCharCode(((raw[j] ?? 0) << 8) | (raw[j + 1] ?? 0));\n }\n out.set(nameId, text);\n seenWindows.add(nameId);\n } else if (platform === 1 && encoding === 0 && !seenWindows.has(nameId)) {\n out.set(nameId, String.fromCharCode(...raw));\n }\n }\n return out;\n}\n\n/* -------------------------------------------------------------------------- */\n/* cmap */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The best Unicode subtable in the font.\n *\n * Preference order is the one every shaper uses: a format 12 full-repertoire\n * table beats a format 4 BMP one, because a face that has both maps astral\n * code points only in the first.\n */\nfunction cmapOf(tables: Tables, subject: string): (codePoint: number) => number {\n const table = required(tables, 'cmap', subject);\n const r = readerOf(table);\n if (table.length < 4) unreadable('cmap table is truncated', subject);\n const count = u16(r, 2);\n\n let best: { offset: number; score: number } | undefined;\n for (let i = 0; i < count; i++) {\n const at = 4 + i * 8;\n if (at + 8 > table.length) break;\n const platform = u16(r, at);\n const encoding = u16(r, at + 2);\n const offset = u32(r, at + 4);\n if (offset + 2 > table.length) continue;\n const unicode =\n (platform === 3 && (encoding === 10 || encoding === 1 || encoding === 0)) || platform === 0;\n if (!unicode) continue;\n const format = u16(readerOf(table.subarray(offset)), 0);\n const score = format === 12 ? 3 : format === 4 ? 2 : format === 6 || format === 0 ? 1 : 0;\n if (score > 0 && (best === undefined || score > best.score)) best = { offset, score };\n }\n if (best === undefined) unreadable('no Unicode cmap subtable', subject);\n\n const sub = table.subarray(best.offset);\n const s = readerOf(sub);\n const format = u16(s, 0);\n\n if (format === 4) {\n const segCount = u16(s, 6) / 2;\n const ends = 14;\n const starts = ends + segCount * 2 + 2;\n const deltas = starts + segCount * 2;\n const ranges = deltas + segCount * 2;\n return (codePoint: number): number => {\n if (codePoint > 0xffff) return 0;\n for (let seg = 0; seg < segCount; seg++) {\n if (u16(s, ends + seg * 2) < codePoint) continue;\n if (u16(s, starts + seg * 2) > codePoint) return 0;\n const rangeOffset = u16(s, ranges + seg * 2);\n if (rangeOffset === 0) return (codePoint + i16(s, deltas + seg * 2)) & 0xffff;\n const at = ranges + seg * 2 + rangeOffset + (codePoint - u16(s, starts + seg * 2)) * 2;\n if (at + 2 > sub.length) return 0;\n const glyph = u16(s, at);\n return glyph === 0 ? 0 : (glyph + i16(s, deltas + seg * 2)) & 0xffff;\n }\n return 0;\n };\n }\n\n if (format === 12) {\n const groups = u32(s, 12);\n return (codePoint: number): number => {\n let low = 0;\n let high = groups - 1;\n while (low <= high) {\n const mid = (low + high) >> 1;\n const at = 16 + mid * 12;\n const start = u32(s, at);\n const end = u32(s, at + 4);\n if (codePoint < start) high = mid - 1;\n else if (codePoint > end) low = mid + 1;\n else return u32(s, at + 8) + (codePoint - start);\n }\n return 0;\n };\n }\n\n if (format === 6) {\n const first = u16(s, 6);\n const entries = u16(s, 8);\n return (codePoint: number): number => {\n const at = codePoint - first;\n return at < 0 || at >= entries ? 0 : u16(s, 10 + at * 2);\n };\n }\n\n // Format 0: a 256-byte byte-to-glyph array.\n return (codePoint: number): number => (codePoint > 0xff ? 0 : u8(s, 6 + codePoint));\n}\n\n/* -------------------------------------------------------------------------- */\n/* kerning */\n/* -------------------------------------------------------------------------- */\n\ntype Kerning = (left: number, right: number) => number;\n\nconst NO_KERNING: Kerning = () => 0;\n\nfunction coverageIndex(r: Reader, at: number, glyph: number): number {\n const format = u16(r, at);\n if (format === 1) {\n const count = u16(r, at + 2);\n for (let i = 0; i < count; i++) if (u16(r, at + 4 + i * 2) === glyph) return i;\n return -1;\n }\n if (format !== 2) return -1;\n const ranges = u16(r, at + 2);\n for (let i = 0; i < ranges; i++) {\n const record = at + 4 + i * 6;\n if (glyph >= u16(r, record) && glyph <= u16(r, record + 2)) {\n return u16(r, record + 4) + (glyph - u16(r, record));\n }\n }\n return -1;\n}\n\nfunction classOf(r: Reader, at: number, glyph: number): number {\n const format = u16(r, at);\n if (format === 1) {\n const start = u16(r, at + 2);\n const count = u16(r, at + 4);\n const index = glyph - start;\n return index < 0 || index >= count ? 0 : u16(r, at + 6 + index * 2);\n }\n if (format !== 2) return 0;\n const ranges = u16(r, at + 2);\n for (let i = 0; i < ranges; i++) {\n const record = at + 4 + i * 6;\n if (glyph >= u16(r, record) && glyph <= u16(r, record + 2)) return u16(r, record + 4);\n }\n return 0;\n}\n\n/** The byte width of a GPOS value record, which is one 16-bit field per set bit. */\nfunction valueSize(format: number): number {\n let bits = 0;\n for (let i = 0; i < 16; i++) if ((format & (1 << i)) !== 0) bits += 1;\n return bits * 2;\n}\n\n/** `XAdvance` is bit 2, and it is the only field a horizontal advance reads. */\nconst X_ADVANCE = 0x0004;\n\n/** `LookupType` 2, pair adjustment: the only positioning that moves an advance. */\nconst PAIR_POS = 2;\n\n/** `LookupType` 9, Extension Positioning, whose subtable names the real type. */\nconst EXTENSION_POS = 9;\n\nfunction pairPosLookup(r: Reader, at: number): Kerning | undefined {\n const format = u16(r, at);\n const valueFormat1 = u16(r, at + 4);\n const valueFormat2 = u16(r, at + 6);\n if ((valueFormat1 & X_ADVANCE) === 0) return undefined;\n const size1 = valueSize(valueFormat1);\n const size2 = valueSize(valueFormat2);\n const coverage = at + u16(r, at + 2);\n\n if (format === 1) {\n const setCount = u16(r, at + 8);\n return (left: number, right: number): number => {\n const index = coverageIndex(r, coverage, left);\n if (index < 0 || index >= setCount) return 0;\n const set = at + u16(r, at + 10 + index * 2);\n const pairs = u16(r, set);\n for (let i = 0; i < pairs; i++) {\n const record = set + 2 + i * (2 + size1 + size2);\n if (u16(r, record) === right) return i16(r, record + 2);\n }\n return 0;\n };\n }\n\n if (format !== 2) return undefined;\n const classDef1 = at + u16(r, at + 8);\n const classDef2 = at + u16(r, at + 10);\n const class1Count = u16(r, at + 12);\n const class2Count = u16(r, at + 14);\n return (left: number, right: number): number => {\n if (coverageIndex(r, coverage, left) < 0) return 0;\n const c1 = classOf(r, classDef1, left);\n const c2 = classOf(r, classDef2, right);\n if (c1 >= class1Count || c2 >= class2Count) return 0;\n const record = at + 16 + (c1 * class2Count + c2) * (size1 + size2);\n return i16(r, record);\n };\n}\n\n/**\n * The pair adjustments behind an `ExtensionPosFormat1` subtable.\n *\n * The extension names the real lookup type and a 32-bit offset from its own\n * start, and may not itself target another, so exactly one level is followed.\n */\nfunction extensionPairPos(r: Reader, at: number): Kerning | undefined {\n const end = r.bytes.length;\n if (at + 8 > end || u16(r, at) !== 1 || u16(r, at + 2) !== PAIR_POS) return undefined;\n const target = at + u32(r, at + 4);\n // A PairPos header is sixteen bytes at its widest and a 32-bit offset can\n // name anything, so one that runs past the table is read as no kerning.\n return target + 16 > end ? undefined : pairPosLookup(r, target);\n}\n\n/**\n * The `kern` feature's pair adjustments, if the font has GPOS.\n *\n * Only the `kern` feature: a font's GPOS also carries mark attachment and\n * cursive positioning, and neither changes an advance. Its lookups are type 2,\n * or the type 9 Extension a font compiler wraps them in.\n */\nfunction gposKerning(tables: Tables): Kerning | undefined {\n const table = tables.get('GPOS');\n if (table === undefined || table.length < 10) return undefined;\n const r = readerOf(table);\n const featureList = u16(r, 6);\n const lookupList = u16(r, 8);\n if (featureList >= table.length || lookupList >= table.length) return undefined;\n\n const wanted = new Set<number>();\n const featureCount = u16(r, featureList);\n for (let i = 0; i < featureCount; i++) {\n const record = featureList + 2 + i * 6;\n if (tagAt(r, record) !== 'kern') continue;\n const feature = featureList + u16(r, record + 4);\n const lookups = u16(r, feature + 2);\n for (let j = 0; j < lookups; j++) wanted.add(u16(r, feature + 4 + j * 2));\n }\n if (wanted.size === 0) return undefined;\n\n const found: Kerning[] = [];\n const lookupCount = u16(r, lookupList);\n for (const index of wanted) {\n if (index >= lookupCount) continue;\n const lookup = lookupList + u16(r, lookupList + 2 + index * 2);\n const type = u16(r, lookup);\n if (type !== PAIR_POS && type !== EXTENSION_POS) continue;\n const subtables = u16(r, lookup + 4);\n for (let i = 0; i < subtables; i++) {\n const at = lookup + u16(r, lookup + 6 + i * 2);\n const pairs = type === PAIR_POS ? pairPosLookup(r, at) : extensionPairPos(r, at);\n if (pairs !== undefined) found.push(pairs);\n }\n }\n if (found.length === 0) return undefined;\n return (left, right) => {\n for (const lookup of found) {\n const adjust = lookup(left, right);\n if (adjust !== 0) return adjust;\n }\n return 0;\n };\n}\n\n/** The pre-OpenType `kern` table, format 0, horizontal subtables only. */\nfunction legacyKerning(tables: Tables): Kerning | undefined {\n const table = tables.get('kern');\n if (table === undefined || table.length < 4) return undefined;\n const r = readerOf(table);\n const subtables = u16(r, 2);\n const pairs = new Map<number, number>();\n let at = 4;\n for (let i = 0; i < subtables && at + 14 <= table.length; i++) {\n const length = u16(r, at + 2);\n const coverage = u16(r, at + 4);\n const horizontal = (coverage & 0x0001) !== 0;\n const format = (coverage >> 8) & 0xff;\n if (horizontal && format === 0) {\n const count = u16(r, at + 6);\n for (let j = 0; j < count; j++) {\n const record = at + 14 + j * 6;\n if (record + 6 > table.length) break;\n pairs.set((u16(r, record) << 16) | u16(r, record + 2), i16(r, record + 4));\n }\n }\n at += length === 0 ? 14 : length;\n }\n if (pairs.size === 0) return undefined;\n return (left, right) => pairs.get((left << 16) | right) ?? 0;\n}\n\n/* -------------------------------------------------------------------------- */\n/* BASE */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The `BASE` horizontal axis' `ideo` coordinate under `DFLT`, in font units.\n *\n * One script and one tag: T13 built a font whose `DFLT`, `latn` and `hani`\n * coordinates all differ and Chromium took `DFLT`, and a second whose `BASE`\n * names every script but `DFLT` and Chromium read none of them. A table this\n * cannot follow is answered with `undefined`, which is what HarfBuzz's\n * sanitiser leaves the browser holding as well.\n */\nfunction ideographicOf(tables: Tables): number | undefined {\n const table = tables.get('BASE');\n if (table === undefined || table.length < 8) return undefined;\n const r = readerOf(table);\n /** An offset that is neither NULL nor short of the bytes it points at. */\n const within = (offset: number, need: number): number | undefined =>\n offset > 0 && offset + need <= table.length ? offset : undefined;\n\n const axis = within(u16(r, 4), 4);\n if (axis === undefined) return undefined;\n const tagList = within(axis + u16(r, axis), 2);\n const scriptList = within(axis + u16(r, axis + 2), 2);\n if (tagList === undefined || scriptList === undefined) return undefined;\n\n const tagCount = u16(r, tagList);\n if (tagList + 2 + tagCount * 4 > table.length) return undefined;\n let tag = -1;\n for (let i = 0; i < tagCount && tag < 0; i++) {\n if (tagAt(r, tagList + 2 + i * 4) === 'ideo') tag = i;\n }\n if (tag < 0) return undefined;\n\n const scriptCount = u16(r, scriptList);\n if (scriptList + 2 + scriptCount * 6 > table.length) return undefined;\n let script: number | undefined;\n for (let i = 0; i < scriptCount && script === undefined; i++) {\n const record = scriptList + 2 + i * 6;\n if (tagAt(r, record) === 'DFLT') script = within(scriptList + u16(r, record + 4), 6);\n }\n if (script === undefined) return undefined;\n\n const values = within(script + u16(r, script), 4);\n if (values === undefined) return undefined;\n if (tag >= u16(r, values + 2) || values + 4 + tag * 2 + 2 > table.length) return undefined;\n const coord = within(values + u16(r, values + 4 + tag * 2), 4);\n if (coord === undefined) return undefined;\n // Formats 2 and 3 put the coordinate in the same field as format 1 and add a\n // device or glyph hint after it, so one read serves all three.\n const format = u16(r, coord);\n return format >= 1 && format <= 3 ? -i16(r, coord + 2) : undefined;\n}\n\n/* -------------------------------------------------------------------------- */\n/* the face */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The vertical metrics a browser reports for the face.\n *\n * Bit 7 wins on DirectWrite and FreeType, which otherwise answer `usWin` and\n * `hhea`; CoreText answers `hhea` either way, 248/248. ADR 0045, ADR 0053.\n */\nfunction metricsOf(tables: Tables, subject: string, backend: FontBackend): FaceMetrics {\n const head = readerOf(required(tables, 'head', subject));\n const unitsPerEm = u16(head, 18);\n if (unitsPerEm <= 0) unreadable('head.unitsPerEm is zero', subject);\n\n const ideographic = ideographicOf(tables);\n const hhea = readerOf(required(tables, 'hhea', subject));\n const hheaPair: MetricPair = { ascent: i16(hhea, 4), descent: -i16(hhea, 6) };\n\n // 78 bytes is `OS/2` version 0, which is every field read below.\n const os2 = tables.get('OS/2');\n if (os2 === undefined || os2.length < 78) {\n // No OS/2 at all is a bare CJK or bitmap face; hhea is then the only source\n // there is, and the browser has nothing else to read either.\n return {\n unitsPerEm,\n ...hheaPair,\n source: 'hhea',\n backend,\n ideographic,\n candidates: { hhea: hheaPair, usWin: undefined, sTypo: undefined, useTypoMetrics: false },\n };\n }\n const r = readerOf(os2);\n const usWin: MetricPair = { ascent: u16(r, 74), descent: u16(r, 76) };\n const sTypo: MetricPair = { ascent: i16(r, 68), descent: -i16(r, 70) };\n const useTypoMetrics = (u16(r, 62) & USE_TYPO_METRICS) !== 0;\n const source =\n backend === 'coretext'\n ? 'hhea'\n : useTypoMetrics\n ? 'sTypo'\n : backend === 'freetype'\n ? 'hhea'\n : 'usWin';\n const chosen = source === 'sTypo' ? sTypo : source === 'hhea' ? hheaPair : usWin;\n return {\n unitsPerEm,\n ...chosen,\n source,\n backend,\n ideographic,\n candidates: { hhea: hheaPair, usWin, sTypo, useTypoMetrics },\n };\n}\n\nfunction advancesOf(tables: Tables, subject: string): (glyph: number) => number {\n const hhea = readerOf(required(tables, 'hhea', subject));\n const metrics = u16(hhea, 34);\n const hmtx = required(tables, 'hmtx', subject);\n const r = readerOf(hmtx);\n if (metrics === 0) unreadable('hhea.numberOfHMetrics is zero', subject);\n return (glyph: number): number => {\n const at = Math.min(glyph, metrics - 1) * 4;\n return at + 2 <= hmtx.length ? u16(r, at) : 0;\n };\n}\n\nconst BOLD_STYLE = /bold|black|heavy|semibold|extrabold|demibold/i;\nconst ITALIC_STYLE = /italic|oblique/i;\n\n/** Read one font out of an already-located table directory. */\nexport function faceOf(tables: Tables, subject: string, backend: FontBackend): Face {\n const names = namesOf(tables, subject);\n const family = names.get(1);\n if (family === undefined || family === '') unreadable('no family name', subject);\n const subfamily = names.get(2) ?? 'Regular';\n const cmap = cmapOf(tables, subject);\n const advance = advancesOf(tables, subject);\n\n // GPOS first, and only then the legacy table: T13 built a font whose two\n // disagreed and Chromium took the GPOS value.\n const kerning = gposKerning(tables) ?? legacyKerning(tables) ?? NO_KERNING;\n\n // `head.macStyle` is the fallback for a face whose subfamily is a design name\n // like `Condensed Light` rather than one of the four standard strings.\n const head = readerOf(required(tables, 'head', subject));\n const macStyle = u16(head, 44);\n\n return {\n family,\n subfamily,\n typographicFamily: names.get(16),\n metrics: metricsOf(tables, subject, backend),\n bold: BOLD_STYLE.test(subfamily) || (macStyle & 0x01) !== 0,\n italic: ITALIC_STYLE.test(subfamily) || (macStyle & 0x02) !== 0,\n advanceOf(codePoint: number): number | undefined {\n const glyph = cmap(codePoint);\n return glyph === 0 ? undefined : advance(glyph);\n },\n kernBetween(left: number, right: number): number {\n const a = cmap(left);\n const b = cmap(right);\n return a === 0 || b === 0 ? 0 : kerning(a, b);\n },\n };\n}\n\n/** Every face in a file, which is one unless the file is a collection. */\nexport function facesIn(bytes: Uint8Array, subject: string, backend: FontBackend): readonly Face[] {\n return fontsIn(bytes, subject).map((tables) => faceOf(tables, subject, backend));\n}\n","/**\n * Which file on this machine is the typeface the deck asked for.\n *\n * The browser answers this with a font stack and never tells us what it chose;\n * here the choice is ours, so it is also reportable - `renderDeck` can say\n * \"Aptos was drawn in Carlito\" because this module knows it was. The\n * substitution table itself is `@pptx-studio/text`'s, so the two renderers\n * cannot fall back differently. ADR 0042.\n */\n\nimport { readdirSync, readFileSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { LAST_RESORT_FAMILIES, TextError, cssFamily, substituteFor } from '@pptx-studio/text';\n\nimport { RenderError } from './errors.js';\nimport { backendFor, facesIn, type Face } from './sfnt.js';\n\nconst FONT_FILE = /\\.(ttf|ttc|otf|otc)$/i;\n\n/** Deep enough for `/usr/share/fonts/truetype/dejavu`, and no deeper. */\nconst MAX_DEPTH = 4;\n\n/** Case and whitespace are not part of a typeface's identity for a lookup. */\nfunction key(family: string): string {\n return family.trim().replace(/\\s+/g, ' ').toLowerCase();\n}\n\n/** Whether a name can be written into the markup that would draw it. */\nfunction emittable(family: string): boolean {\n try {\n cssFamily(family);\n return true;\n } catch (error) {\n if (error instanceof TextError && error.code === 'TEXT_FONT_FAMILY') return false;\n throw error;\n }\n}\n\n/** Code unit order, which is the same on every machine and in every locale. */\nfunction compare(a: string, b: string): number {\n if (a === b) return 0;\n return a < b ? -1 : 1;\n}\n\n/** Where fonts live on this platform, whether or not the directories exist. */\nexport function systemFontDirectories(platform: string = process.platform): readonly string[] {\n const home = homedir();\n if (platform === 'win32') {\n const root = process.env['SystemRoot'] ?? 'C:\\\\Windows';\n const local = process.env['LOCALAPPDATA'];\n return [\n join(root, 'Fonts'),\n ...(local === undefined ? [] : [join(local, 'Microsoft', 'Windows', 'Fonts')]),\n ];\n }\n if (platform === 'darwin') {\n return ['/System/Library/Fonts', '/Library/Fonts', join(home, 'Library', 'Fonts')];\n }\n return [\n '/usr/share/fonts',\n '/usr/local/share/fonts',\n join(home, '.local', 'share', 'fonts'),\n join(home, '.fonts'),\n ];\n}\n\nfunction filesUnder(directory: string, depth: number, out: string[]): void {\n if (depth > MAX_DEPTH) return;\n let entries;\n try {\n entries = readdirSync(directory, { withFileTypes: true });\n } catch {\n // A directory that is not there, or not readable, contributes no fonts.\n // Only a directory the caller named explicitly is an error, and `indexFonts`\n // checks those before it gets here.\n return;\n }\n // By name, because `readdir` order is the filesystem's own and two machines\n // holding the same files return it differently.\n for (const entry of [...entries].sort((a, b) => compare(a.name, b.name))) {\n const path = join(directory, entry.name);\n if (entry.isDirectory()) filesUnder(path, depth + 1, out);\n else if (FONT_FILE.test(entry.name)) out.push(path);\n }\n}\n\nexport interface IndexedFace {\n readonly face: Face;\n readonly file: string;\n}\n\n/** What the library found for a typeface the deck named. */\nexport interface Resolved {\n readonly face: Face;\n /** The typeface the deck asked for. */\n readonly asked: string;\n /** The family actually drawn in, which differs when a substitute was used. */\n readonly drawn: string;\n readonly file: string;\n readonly substituted: boolean;\n}\n\nexport interface FontLibrary {\n /** Every face found, for the diagnostics and for a test to count. */\n readonly indexed: readonly IndexedFace[];\n /** The directories that were scanned, in order. */\n readonly directories: readonly string[];\n resolve(family: string, bold: boolean, italic: boolean): Resolved | undefined;\n}\n\nexport interface IndexOptions {\n /** Directories to scan before the system ones. Each must exist. */\n readonly extra?: readonly string[];\n /** Whether to scan this platform's own font directories. Default true. */\n readonly system?: boolean;\n readonly platform?: string;\n}\n\n/**\n * The style slot a face fills.\n *\n * Two bits rather than a weight axis, because DrawingML has no weight axis:\n * `a:rPr/@b` is a boolean and \"Roboto Light\" is a typeface name, not a weight.\n */\nfunction slot(bold: boolean, italic: boolean): number {\n return (bold ? 1 : 0) | (italic ? 2 : 0);\n}\n\n/** One family and the four style slots it fills. */\ninterface Family {\n /** The spelling to report, as the first face claiming it spells the name. */\n readonly name: string;\n readonly slots: (IndexedFace | undefined)[];\n}\n\n/**\n * The names a typeface is a variation of, longest first.\n *\n * DrawingML has no weight axis, so `Calibri Light` is a typeface name rather\n * than Calibri at a weight, and Calibri is the nearer face to draw it in.\n */\nfunction shorterNames(family: string): readonly string[] {\n const words = family.trim().split(/\\s+/);\n const names: string[] = [];\n for (let at = words.length - 1; at > 0; at--) names.push(words.slice(0, at).join(' '));\n return names;\n}\n\n/**\n * The families to try for one this machine lacks, in order.\n *\n * The measured chain first - `@pptx-studio/text`'s table and then what\n * PowerPoint itself falls back to, ADR 0033 - and the shorter forms of the\n * asked-for name only after it, where no measurement reaches.\n */\nfunction standInsFor(family: string): readonly string[] {\n return [\n substituteFor(family)?.use,\n ...LAST_RESORT_FAMILIES,\n ...shorterNames(family).flatMap((name) => [name, substituteFor(name)?.use]),\n ].filter((name): name is string => name !== undefined);\n}\n\n/**\n * Read every font file under the given directories, once.\n *\n * A file that will not parse is skipped rather than fatal: a font directory on\n * a real machine holds `.ttf` files that are bitmap-only, damaged, or not fonts\n * at all, and one of them must not stop a deck from rendering.\n */\nexport function indexFonts(options: IndexOptions = {}): FontLibrary {\n for (const directory of options.extra ?? []) {\n try {\n if (!statSync(directory).isDirectory()) {\n throw new RenderError('CLI_FONT_DIR', `${directory} is not a directory`, directory);\n }\n } catch (error) {\n if (error instanceof RenderError) throw error;\n throw new RenderError('CLI_FONT_DIR', `no such directory: ${directory}`, directory);\n }\n }\n\n const directories = [\n ...(options.extra ?? []),\n ...(options.system === false ? [] : systemFontDirectories(options.platform)),\n ];\n\n const files: string[] = [];\n for (const directory of directories) filesUnder(directory, 0, files);\n\n // The face box comes out of a different table per rasteriser, so the reader\n // answers for the machine whose fonts these are. ADR 0045.\n const backend = backendFor(options.platform ?? process.platform);\n\n const indexed: IndexedFace[] = [];\n const byFamily = new Map<string, Family>();\n const claim = (family: string, entry: IndexedFace): void => {\n const at = key(family);\n // A blank `name` ID 16 identifies nothing, and a name the CSS shorthand\n // refuses can never be drawn, so neither claims a family.\n if (at === '' || !emittable(family)) return;\n const found = byFamily.get(at) ?? {\n name: family,\n slots: [undefined, undefined, undefined, undefined],\n };\n // First file wins, so an earlier `--font-dir` beats a system face of the\n // same name and the caller can override without uninstalling anything.\n found.slots[slot(entry.face.bold, entry.face.italic)] ??= entry;\n byFamily.set(at, found);\n };\n\n for (const file of files) {\n let faces: readonly Face[];\n try {\n faces = facesIn(new Uint8Array(readFileSync(file)), file, backend);\n } catch {\n continue;\n }\n for (const face of faces) {\n const entry: IndexedFace = { face, file };\n indexed.push(entry);\n claim(face.family, entry);\n // Name ID 16 is what a large family is known by once it outgrows the four\n // style slots, and it is the name a deck spells - `Segoe UI` for the face\n // whose ID 1 is `Segoe UI Semibold`.\n if (face.typographicFamily !== undefined) claim(face.typographicFamily, entry);\n }\n }\n\n /** The nearest slot to the one asked for: exact, then drop italic, then bold. */\n const pickIn = (found: Family, bold: boolean, italic: boolean): IndexedFace | undefined => {\n const wanted = [\n slot(bold, italic),\n slot(bold, false),\n slot(false, italic),\n slot(false, false),\n 0,\n 1,\n 2,\n 3,\n ];\n for (const at of wanted) {\n const entry = found.slots[at];\n if (entry !== undefined) return entry;\n }\n return undefined;\n };\n\n const drawnIn = (\n name: string,\n bold: boolean,\n italic: boolean,\n asked: string,\n ): Resolved | undefined => {\n const family = byFamily.get(key(name));\n if (family === undefined) return undefined;\n const found = pickIn(family, bold, italic);\n if (found === undefined) return undefined;\n return {\n face: found.face,\n asked,\n drawn: name,\n file: found.file,\n substituted: key(name) !== key(asked),\n };\n };\n\n return {\n indexed,\n directories,\n resolve(family: string, bold: boolean, italic: boolean): Resolved | undefined {\n for (const name of [family, ...standInsFor(family)]) {\n const found = drawnIn(name, bold, italic, family);\n if (found !== undefined) return found;\n }\n // Every named stand-in is absent too. The browser's stack ends in a\n // generic and this cannot, so the first family by name draws it: the\n // choice two machines holding the same faces both make.\n for (const [, entry] of [...byFamily].sort((a, b) => compare(a[0], b[0]))) {\n const found = pickIn(entry, bold, italic);\n if (found !== undefined) {\n return {\n face: found.face,\n asked: family,\n drawn: entry.name,\n file: found.file,\n substituted: true,\n };\n }\n }\n return undefined;\n },\n };\n}\n","/**\n * `TextMeasurer` and `FaceBoxProbe` over font tables instead of a canvas.\n *\n * This is a second measurement engine, and `@pptx-studio/text` says in as many\n * words that nothing inside it may measure by a second route. That rule holds:\n * this is outside it, in the one package where Node exists, and it is here\n * because the browser's engine is not available to a server. What makes it safe\n * is that T13 measured Chromium's arithmetic rather than guessing it, so the two\n * engines agree exactly on a face they both have. ADR 0042.\n */\n\nimport {\n FACE_BOX_PX,\n fontStack,\n kerningEnabled,\n type FaceBox,\n type FaceBoxProbe,\n type RunFont,\n type TextMeasurer,\n} from '@pptx-studio/text';\n\nimport type { FontLibrary, Resolved } from './faces.js';\nimport { RenderError } from './errors.js';\nimport type { FontBackend } from './sfnt.js';\n\n/**\n * The fixed-point step Chromium reports an advance in.\n *\n * Quantising each glyph advance toward zero and each kern adjustment to nearest\n * fits all 540 of T13's widths, where summing exact floats fits 234 and is out\n * by up to 1.04e-4 px. ADR 0042.\n */\nconst FIXED = 65536;\n\n/** CoreText's `Fixed`: the em ratio is held as 16.16 before the box rounds. ADR 0053. */\nconst EM_FIXED = 65536;\n\n/**\n * `hmtx.advanceWidth` is a `UFWORD`, so this is never negative and truncation\n * and flooring are one rule. ADR 0042.\n */\nfunction quantiseAdvance(px: number): number {\n return Math.trunc(px * FIXED) / FIXED;\n}\n\nfunction quantiseKern(px: number): number {\n return Math.round(px * FIXED) / FIXED;\n}\n\n/**\n * A box metric as the browser probe reports it: read at `FACE_BOX_PX`, rounded\n * half up to the pixel, and handed back as a fraction of the em. CoreText holds\n * the em ratio as 16.16 fixed point first. T13 30/30, T14 248/248. ADR 0053.\n */\nfunction boxPixels(units: number, unitsPerEm: number, backend: FontBackend): number {\n const px =\n backend === 'coretext'\n ? (Math.round((units / unitsPerEm) * EM_FIXED) / EM_FIXED) * FACE_BOX_PX\n : (units * FACE_BOX_PX) / unitsPerEm;\n return Math.floor(px + 0.5) / FACE_BOX_PX;\n}\n\nexport interface FaceUse {\n readonly asked: string;\n readonly drawn: string;\n readonly file: string;\n readonly substituted: boolean;\n}\n\nexport interface FontMeasurer {\n readonly measurer: TextMeasurer;\n readonly faceBox: FaceBoxProbe;\n /** The CSS family list a run is drawn in: the face that measured it, then the deck's own stack. */\n readonly cssFamilyFor: (font: RunFont) => string;\n /** Every typeface asked for, and what it was drawn in. */\n used(): readonly FaceUse[];\n /** Code points no face in the library could draw. */\n missing(): readonly number[];\n}\n\n/**\n * A measurer bound to one library.\n *\n * Both probes cache by family, because a slide asks for the same handful of\n * typefaces thousands of times and nothing can change between two asks.\n */\nexport function createFontMeasurer(library: FontLibrary): FontMeasurer {\n const resolved = new Map<string, Resolved>();\n const missing = new Set<number>();\n /** Which face draws a code point the asked-for face has no glyph for. */\n const fallbacks = new Map<string, Resolved | null>();\n\n const faceFor = (family: string, bold: boolean, italic: boolean): Resolved => {\n const cacheKey = `${family}\\u0000${bold ? 'b' : ''}${italic ? 'i' : ''}`;\n const cached = resolved.get(cacheKey);\n if (cached !== undefined) return cached;\n const found = library.resolve(family, bold, italic);\n if (found === undefined) {\n // The library resolves any family it holds a face for, so this is the\n // empty library: there is nothing at all to draw with.\n const where =\n library.directories.length === 0\n ? 'no directory was searched'\n : `nothing was found in ${library.directories.join(', ')}`;\n throw new RenderError(\n 'CLI_NO_FACE',\n `no face on this machine can stand in for ${JSON.stringify(family)}: ` +\n `the font library is empty, ${where}`,\n family,\n );\n }\n resolved.set(cacheKey, found);\n return found;\n };\n\n /**\n * The advance of one code point, in font units over its own em.\n *\n * A face that lacks the glyph does not draw a blank: the browser would fall\n * back per character, so the whole index is searched once per code point and\n * the answer cached. A code point nothing has is recorded and contributes the\n * face's own `.notdef` width, which is what is drawn.\n */\n const advanceOf = (face: Resolved, codePoint: number): { units: number; em: number } => {\n const own = face.face.advanceOf(codePoint);\n if (own !== undefined) return { units: own, em: face.face.metrics.unitsPerEm };\n\n const cacheKey = String(codePoint);\n let stand = fallbacks.get(cacheKey);\n if (stand === undefined) {\n stand = null;\n for (const entry of library.indexed) {\n if (entry.face.advanceOf(codePoint) !== undefined) {\n stand = { ...face, face: entry.face, drawn: entry.face.family, file: entry.file };\n break;\n }\n }\n fallbacks.set(cacheKey, stand);\n }\n if (stand === null) {\n missing.add(codePoint);\n return { units: 0, em: face.face.metrics.unitsPerEm };\n }\n const units = stand.face.advanceOf(codePoint) ?? 0;\n return { units, em: stand.face.metrics.unitsPerEm };\n };\n\n const measurer: TextMeasurer = {\n measure(text: string, font: RunFont) {\n if (!Number.isFinite(font.sz) || font.sz <= 0) {\n throw new RenderError(\n 'CLI_FONT_SIZE',\n `font size ${String(font.sz)} is not a positive size`,\n font.family,\n );\n }\n const face = faceFor(font.family, font.bold === true, font.italic === true);\n // One CSS pixel is one point here, exactly as in the canvas measurer.\n const px = font.sz / 100;\n const kerns = kerningEnabled(font.kern, font.sz);\n const spacing = (font.spc ?? 0) / 100;\n\n const points = [...text];\n let width = 0;\n for (let i = 0; i < points.length; i++) {\n const codePoint = points[i]?.codePointAt(0) ?? 0;\n const { units, em } = advanceOf(face, codePoint);\n width += quantiseAdvance((units * px) / em);\n // `@spc` is an absolute length applied after every character, the last\n // included - T2 scored that 18/18 - and Chromium's `letterSpacing` does\n // the same, which is why the canvas measurer can pass it straight in.\n width += spacing;\n if (kerns && i + 1 < points.length) {\n const next = points[i + 1]?.codePointAt(0) ?? 0;\n const adjust = face.face.kernBetween(codePoint, next);\n if (adjust !== 0) {\n width += quantiseKern((adjust * px) / face.face.metrics.unitsPerEm);\n }\n }\n }\n return { width };\n },\n };\n\n const boxes = new Map<string, FaceBox>();\n const faceBox: FaceBoxProbe = {\n box(family: string): FaceBox {\n const cached = boxes.get(family);\n if (cached !== undefined) return cached;\n const { metrics } = faceFor(family, false, false).face;\n const descent = boxPixels(metrics.descent, metrics.unitsPerEm, metrics.backend);\n // Chromium answers the `BASE` `ideo` coordinate where the face has one and\n // its own rounded box descent where it does not, 38 of 38 in T13.\n const ideographic =\n metrics.ideographic === undefined ? descent : metrics.ideographic / metrics.unitsPerEm;\n const box: FaceBox = {\n ascent: boxPixels(metrics.ascent, metrics.unitsPerEm, metrics.backend),\n descent,\n // Anything outside the em is unusable to `uprightPen`, and zero is what\n // the browser probe answers there. `packages/text/src/lines/baseline.ts`.\n ideographic: ideographic > 0 && ideographic < 1 ? ideographic : 0,\n };\n boxes.set(family, box);\n return box;\n },\n };\n\n return {\n measurer,\n faceBox,\n cssFamilyFor(font: RunFont): string {\n const face = faceFor(font.family, font.bold === true, font.italic === true);\n return fontStack(face.asked, face.drawn);\n },\n used(): readonly FaceUse[] {\n const seen = new Map<string, FaceUse>();\n for (const face of resolved.values()) {\n seen.set(face.asked, {\n asked: face.asked,\n drawn: face.drawn,\n file: face.file,\n substituted: face.substituted,\n });\n }\n return [...seen.values()].sort((a, b) => (a.asked < b.asked ? -1 : 1));\n },\n missing(): readonly number[] {\n return [...missing].sort((a, b) => a - b);\n },\n };\n}\n","/**\n * `pptx-studio render` - slides to SVG, with no browser anywhere.\n *\n * Every part of the picture except text was already reachable from Node:\n * geometry, fills, strokes, effects and images are pure functions over the\n * model, and an image's size comes out of its own header rather than a decoder.\n * Text was the one thing that needed a canvas, and `measure.ts` is what replaces\n * it. ADR 0042.\n */\n\nimport { mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { PartStore } from '@pptx-studio/opc';\nimport { loadDocument } from '@pptx-studio/model';\nimport { renderSlide, type MediaResolver } from '@pptx-studio/render-svg';\n\nimport { RenderError } from './errors.js';\nimport { indexFonts, type FontLibrary } from './faces.js';\nimport { createFontMeasurer, type FaceUse } from './measure.js';\n\n/** What a slide is drawn at when the caller says nothing. PowerPoint's own. */\nexport const DEFAULT_WIDTH = 1920;\n\n/** What to draw. Every field has a default, so `renderDeck(bytes)` is a whole call. */\nexport interface RenderDeckOptions {\n /** 1-based. Omitted, or `null`, is every slide. */\n readonly slide?: number | null;\n /** The `width` attribute in CSS pixels; the height follows the deck's aspect. */\n readonly width?: number;\n /** Searched before the platform's own, so a face can be overridden without installing it. */\n readonly fontDirs?: readonly string[];\n /** Also look in this platform's font directories. Default true. */\n readonly systemFonts?: boolean;\n /** Draw text. `false` draws geometry only and asks no font questions. Default true. */\n readonly text?: boolean;\n}\n\n/** What the verb adds: where the markup goes, and what is said about it. */\nexport interface RenderOptions extends RenderDeckOptions {\n /** A directory for many slides, a file for one, or `null` for stdout. */\n readonly out: string | null;\n readonly json: boolean;\n readonly quiet: boolean;\n}\n\n/** Text is drawn unless the caller says otherwise. */\nfunction drawsText(options: RenderDeckOptions): boolean {\n return options.text ?? true;\n}\n\nexport interface RenderedSlide {\n /** 1-based, as the flag and the file name spell it. */\n readonly number: number;\n readonly svg: string;\n}\n\nexport interface RenderResult {\n readonly slides: readonly RenderedSlide[];\n readonly width: number;\n readonly height: number;\n /** Every typeface the deck asked for, and what drew it. Empty with `--no-text`. */\n readonly fonts: readonly FaceUse[];\n /** Code points no indexed face could draw. */\n readonly missing: readonly number[];\n readonly fontDirectories: readonly string[];\n readonly facesIndexed: number;\n}\n\n/** The media resolver: an rId means the rels of the part the fill was written in. */\nfunction mediaFrom(store: PartStore): MediaResolver {\n return (embed: string, part: string) => {\n const target = store.relationships(part).targetOf(embed);\n if (target === undefined) return undefined;\n const contentType = store.contentTypeOf(target);\n if (contentType === undefined) return undefined;\n return { bytes: store.read(target), contentType };\n };\n}\n\n/**\n * Render a deck that is already in memory.\n *\n * The library entry point: no file system, no process, no stdout. `runRender` is\n * the verb wrapped around it, and the three fields it adds are its own.\n */\nexport function renderDeck(bytes: Uint8Array, options: RenderDeckOptions = {}): RenderResult {\n const width = options.width ?? DEFAULT_WIDTH;\n if (!Number.isInteger(width) || width < 1) {\n throw new RenderError(\n 'CLI_WIDTH',\n `a width of ${String(width)} is not a positive whole number of pixels`,\n String(width),\n );\n }\n const slide = options.slide ?? null;\n\n const store = PartStore.open(bytes);\n const document = loadDocument(store);\n const size = document.slideSize;\n const height = Math.round((width * size.cy) / size.cx);\n\n if (slide !== null) {\n const count = document.slides.length;\n if (!Number.isInteger(slide) || slide < 1 || slide > count) {\n throw new RenderError(\n 'CLI_NO_SLIDE',\n `slide ${String(slide)}: the deck has ${String(count)} slide(s)`,\n String(slide),\n );\n }\n }\n\n let library: FontLibrary | null = null;\n const fonts = drawsText(options)\n ? createFontMeasurer(\n (library = indexFonts({\n extra: options.fontDirs ?? [],\n system: options.systemFonts !== false,\n })),\n )\n : null;\n\n const media = mediaFrom(store);\n const wanted =\n slide === null\n ? document.slides.map((sheet, at) => ({ sheet, number: at + 1 }))\n : [{ sheet: document.slides[slide - 1]!, number: slide }];\n\n const slides = wanted.map(({ sheet, number }) => ({\n number,\n svg: renderSlide(sheet, size, {\n width,\n height,\n idPrefix: `s${String(number)}`,\n media,\n text:\n fonts === null\n ? false\n : {\n defaultTextStyle: document.defaultTextStyle,\n measurer: fonts.measurer,\n faceBox: fonts.faceBox,\n cssFamilyFor: fonts.cssFamilyFor,\n },\n }),\n }));\n\n return {\n slides,\n width,\n height,\n fonts: fonts?.used() ?? [],\n missing: fonts?.missing() ?? [],\n fontDirectories: library?.directories ?? [],\n facesIndexed: library?.indexed.length ?? 0,\n };\n}\n\n/** `slide-03.svg`, so a directory listing sorts the way the deck reads. */\nfunction fileNameFor(number: number, count: number): string {\n const width = Math.max(2, String(count).length);\n return `slide-${String(number).padStart(width, '0')}.svg`;\n}\n\nfunction isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Where each slide's markup goes.\n *\n * One slide to a path that is not an existing directory writes that file;\n * anything else writes a file per slide into a directory, created if needed.\n * A path ending in `.svg` with more than one slide is a mistake worth naming\n * rather than silently turning into a directory.\n */\nfunction write(result: RenderResult, out: string): readonly string[] {\n const single = result.slides.length === 1 && !isDirectory(out);\n if (single) {\n const first = result.slides[0]!;\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, first.svg, 'utf8');\n return [out];\n }\n if (out.toLowerCase().endsWith('.svg')) {\n throw new RenderError(\n 'CLI_OUTPUT_PATH',\n `--out ${out} names one file but ${String(result.slides.length)} slides were rendered; ` +\n 'name a directory, or pass --slide',\n out,\n );\n }\n mkdirSync(out, { recursive: true });\n return result.slides.map((slide) => {\n const path = join(out, fileNameFor(slide.number, result.slides.length));\n writeFileSync(path, slide.svg, 'utf8');\n return path;\n });\n}\n\nfunction report(result: RenderResult, written: readonly string[], options: RenderOptions): string {\n const lines: string[] = [];\n const slides = `${String(result.slides.length)} slide(s) at ${String(result.width)}x${String(result.height)}`;\n lines.push(\n written.length === 0\n ? slides\n : `${slides} -> ${written.length === 1 ? written[0]! : `${String(written.length)} files`}`,\n );\n\n if (drawsText(options)) {\n const substituted = result.fonts.filter((font) => font.substituted);\n lines.push(\n `${String(result.fonts.length)} typeface(s) from ${String(result.facesIndexed)} indexed face(s)` +\n (substituted.length === 0 ? '' : `, ${String(substituted.length)} substituted`),\n );\n for (const font of substituted) lines.push(` ${font.asked} -> ${font.drawn}`);\n if (result.missing.length > 0) {\n const shown = result.missing\n .slice(0, 8)\n .map((code) => `U+${code.toString(16).toUpperCase().padStart(4, '0')}`);\n lines.push(\n ` no face has ${String(result.missing.length)} code point(s): ${shown.join(' ')}` +\n (result.missing.length > shown.length ? ' ...' : ''),\n );\n }\n }\n return `${lines.join('\\n')}\\n`;\n}\n\n/** Read, render, write, and return an exit code. Never calls `process.exit`. */\nexport function runRender(\n file: string,\n options: RenderOptions,\n out: (text: string) => void,\n): number {\n const result = renderDeck(new Uint8Array(readFileSync(file)), options);\n\n if (options.json) {\n const written = options.out === null ? [] : write(result, options.out);\n out(\n `${JSON.stringify(\n {\n slides: result.slides.map((slide) => ({\n number: slide.number,\n bytes: slide.svg.length,\n })),\n width: result.width,\n height: result.height,\n fonts: result.fonts,\n missing: result.missing.map((code) => `U+${code.toString(16).toUpperCase()}`),\n fontDirectories: result.fontDirectories,\n facesIndexed: result.facesIndexed,\n written,\n },\n null,\n 2,\n )}\\n`,\n );\n return 0;\n }\n\n if (options.out === null) {\n for (const slide of result.slides) out(slide.svg);\n return 0;\n }\n\n const written = write(result, options.out);\n if (!options.quiet) out(report(result, written, options));\n return 0;\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { readZip } from '@pptx-studio/opc';\nimport {\n roundTripPackage,\n summarizeRoundTrip,\n type Difference,\n type RoundTripReport,\n} from '@pptx-studio/writer';\n\n/**\n * `pptx-studio roundtrip deck.pptx`\n *\n * Read a deck, write it back, and say whether it is still the same deck.\n *\n * ## What it is for\n *\n * It is the gate of Phase 1 with a command line on it. Sub-phase 1.6 runs it\n * over the corpus on every pull request, and the number it prints is the one\n * the README's badge carries - so this is a place where the output format is\n * part of the deliverable rather than decoration.\n *\n * It is also the first thing to reach for when a deck misbehaves. `validate`\n * answers \"is this package well formed\"; this answers \"did we change it\", which\n * is a different question and usually the one that matters, because the packages\n * that cause trouble are the ones that are well formed and subtly different.\n *\n * ## What \"the same deck\" means here\n *\n * Not the same bytes. The plan rules that out and `comparePackages` explains\n * why at length: entry order, deflate level, timestamps and attribute order all\n * differ legitimately between two archives holding one document. What is\n * compared is the canonical XML of every XML part, the relationship graph with\n * ids treated as opaque labels, and the SHA-256 of everything else.\n *\n * ## The exit code\n *\n * `0` when there is nothing to report. `1` when the two packages differ, and\n * `1` as well when the export was refused outright - the caller in CI wants one\n * bit, and both of those are \"this deck did not round-trip\". The two are still\n * distinguishable on stderr, because they need completely different work.\n */\n\nexport interface RoundTripOptions {\n /** Print the comparison as JSON instead of as text. */\n readonly json: boolean;\n /** Show only the differences, not the tally. */\n readonly quiet: boolean;\n /** Write the report to this path instead of stdout. */\n readonly out: string | null;\n /**\n * Also write the exported package here.\n *\n * The point of the flag is what happens next: open the file in PowerPoint.\n * Nothing in this repository can assert that a file opens clean, and until\n * 1.5 scripts it there is no substitute for doing it by hand.\n */\n readonly write: string | null;\n}\n\nexport const ROUNDTRIP_DEFAULTS: RoundTripOptions = {\n json: false,\n quiet: false,\n out: null,\n write: null,\n};\n\nexport interface RoundTripFileResult {\n readonly comparison: RoundTripReport;\n readonly output: string;\n readonly bytes: Uint8Array;\n readonly exitCode: number;\n}\n\nfunction describeDifference(difference: Difference): string {\n // Two lines, the second indented, because a `detail` may itself be three\n // lines when it carries an excerpt of the markup either side.\n const body = difference.detail\n .split('\\n')\n .map((line) => ' ' + line.trimEnd())\n .join('\\n');\n return ' ' + difference.kind.padEnd(13) + difference.part + '\\n' + body;\n}\n\n/** What the header line reports, gathered once so the formatter is testable on its own. */\nexport interface RoundTripStats {\n readonly bytesIn: number;\n readonly bytesOut: number;\n readonly entriesIn: number;\n readonly entriesOut: number;\n readonly rewritten: number;\n readonly streamed: number;\n}\n\n/**\n * Render a comparison.\n *\n * Exported so that the branch that lists differences can be tested, which it\n * otherwise could not be: no deck in the corpus makes this writer produce one,\n * which is the point of the whole phase and leaves the most important output in\n * the file as the only output nothing exercises.\n */\nexport function formatRoundTrip(\n path: string,\n stats: RoundTripStats,\n comparison: RoundTripReport,\n quiet: boolean,\n): string {\n const lines: string[] = [];\n if (!quiet) {\n lines.push(\n 'roundtrip ' + path,\n '',\n ' read ' + String(stats.bytesIn) + ' bytes, ' + String(stats.entriesIn) + ' entries',\n ' written ' + String(stats.bytesOut) + ' bytes, ' + String(stats.entriesOut) + ' entries',\n ' export ' +\n String(stats.rewritten) +\n ' part(s) re-serialized, ' +\n String(stats.streamed) +\n ' streamed',\n ' compared ' + summarizeRoundTrip(comparison),\n '',\n );\n }\n\n if (comparison.ok) {\n lines.push(' no differences');\n } else {\n lines.push(' ' + String(comparison.differences.length) + ' difference(s)', '');\n for (const difference of comparison.differences) lines.push(describeDifference(difference), '');\n }\n\n if (!quiet && comparison.relabelled.length > 0) {\n // Never true for a package this writer produced, so when it is true it is\n // worth a line: it means the file being compared came from somewhere else.\n lines.push(\n '',\n ' ' + String(comparison.relabelled.length) + ' relationship id(s) renamed:',\n ...comparison.relabelled\n .slice(0, 10)\n .map((entry) => ' ' + entry.source + ' ' + entry.from + ' -> ' + entry.to),\n );\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nexport function roundTripFile(\n path: string,\n options: RoundTripOptions = ROUNDTRIP_DEFAULTS,\n): RoundTripFileResult {\n const original = new Uint8Array(readFileSync(path));\n const result = roundTripPackage(original);\n const { comparison } = result;\n\n const stats: RoundTripStats = {\n bytesIn: original.length,\n bytesOut: result.exported.bytes.length,\n entriesIn: readZip(original).entries.length,\n entriesOut: readZip(result.exported.bytes).entries.length,\n rewritten: result.exported.rewritten.length,\n streamed: result.exported.streamed,\n };\n\n const output = options.json\n ? JSON.stringify(\n {\n file: path,\n ok: comparison.ok,\n bytesIn: stats.bytesIn,\n bytesOut: stats.bytesOut,\n rewritten: result.exported.rewritten,\n counts: comparison.counts,\n relabelled: comparison.relabelled,\n differences: comparison.differences,\n parts: comparison.parts,\n },\n null,\n 2,\n ) + '\\n'\n : formatRoundTrip(path, stats, comparison, options.quiet);\n\n return {\n comparison,\n output,\n bytes: result.exported.bytes,\n exitCode: comparison.ok ? 0 : 1,\n };\n}\n\n/** Run `roundTripFile` and put the results where the options say. */\nexport function runRoundTrip(\n path: string,\n options: RoundTripOptions,\n write: (text: string) => void,\n): number {\n const result = roundTripFile(path, options);\n if (options.write !== null) writeFileSync(options.write, result.bytes);\n if (options.out === null) write(result.output);\n else writeFileSync(options.out, result.output);\n return result.exitCode;\n}\n","import { readFileSync, writeFileSync } from 'node:fs';\nimport { formatReport, validatePackage, type Report } from '@pptx-studio/validate';\n\n/**\n * `pptx-studio validate deck.pptx`\n *\n * The rules live in `@pptx-studio/validate`, which is a browser package with no\n * Node in it - the same split `inspect` has, for the same reason. What is left\n * here is reading a path, writing a stream, and choosing an exit code.\n *\n * ## What this command can and cannot ask\n *\n * Six of the twenty-nine rules compare a package against the package **as it\n * was opened**, and a file dropped on the command line has no such history.\n * They are skipped, and the report says so by name rather than counting them as\n * passes - `--quiet` still prints the skipped list, because a report that\n * silently means less than it looks like is the failure mode this package\n * exists to avoid.\n *\n * That makes `validate` a diagnostic rather than the export gate. The gate is\n * `assertValid`, called from the writer in sub-phase 1.3 with both packages in\n * hand; this is what you run against a file somebody sent you.\n *\n * ## The exit code\n *\n * `1` when anything fatal was found, `0` otherwise; a warning never fails the\n * command. With no baseline every fatal is treated as ours, which is the safe\n * direction when the question \"did we break this\" cannot be asked at all.\n */\n\nexport interface ValidateOptions {\n /** Print the report as JSON instead of as text. */\n readonly json: boolean;\n /** Append each rule's rationale, once per rule that fired. */\n readonly explain: boolean;\n /** Hide warnings; show only what would refuse an export. */\n readonly quiet: boolean;\n /** Write to this path instead of stdout. */\n readonly out: string | null;\n}\n\nexport const VALIDATE_DEFAULTS: ValidateOptions = {\n json: false,\n explain: false,\n quiet: false,\n out: null,\n};\n\nexport interface ValidateResult {\n readonly report: Report;\n readonly output: string;\n readonly exitCode: number;\n}\n\nexport function validateFile(\n path: string,\n options: ValidateOptions = VALIDATE_DEFAULTS,\n): ValidateResult {\n const bytes = new Uint8Array(readFileSync(path));\n const report = validatePackage({ bytes });\n\n const output = options.json\n ? JSON.stringify(report, null, 2) + '\\n'\n : formatReport(report, { explain: options.explain, warnings: !options.quiet }) + '\\n';\n\n const fatal = report.findings.filter((finding) => finding.severity === 'fatal').length;\n return { report, output, exitCode: fatal > 0 ? 1 : 0 };\n}\n\n/** Run `validateFile` and put the result where the options say. */\nexport function runValidate(\n path: string,\n options: ValidateOptions,\n write: (text: string) => void,\n): number {\n const result = validateFile(path, options);\n if (options.out === null) write(result.output);\n else writeFileSync(options.out, result.output);\n return result.exitCode;\n}\n","import { readFileSync } from 'node:fs';\nimport { parseArgs } from 'node:util';\nimport { isOpcError } from '@pptx-studio/opc';\nimport { isValidateError } from '@pptx-studio/validate';\nimport { BISECT_DEFAULTS, runBisect, type BisectOptions } from './bisect.js';\nimport { INSPECT_DEFAULTS, runInspect, type InspectOptions } from './inspect.js';\nimport { isRenderError } from './render/errors.js';\nimport { DEFAULT_WIDTH, runRender, type RenderOptions } from './render/render.js';\nimport { runRoundTrip, type RoundTripOptions } from './roundtrip.js';\nimport { runValidate, type ValidateOptions } from './validate.js';\n\n/**\n * The command line, on `node:util.parseArgs` rather than a dependency.\n *\n * A verb the plan promises but does not ship yet (`PLANNED`) is in the help\n * text with the sub-phase that brings it, so asking for it says so rather than\n * \"unknown command\".\n */\n\ninterface PlannedVerb {\n readonly name: string;\n readonly summary: string;\n readonly phase: string;\n}\n\nconst PLANNED: readonly PlannedVerb[] = [\n { name: 'resolve', summary: 'show where a resolved property came from', phase: '7.x' },\n];\n\nfunction version(): string {\n // Resolves the same from `dist/cli.js` and from `src/main.ts`, so a run\n // straight off the source reports the version the package will publish.\n const manifest: unknown = JSON.parse(\n readFileSync(new URL('../package.json', import.meta.url), 'utf8'),\n );\n return typeof manifest === 'object' && manifest !== null && 'version' in manifest\n ? String(manifest.version)\n : '0.0.0';\n}\n\nfunction usage(): string {\n const planned = PLANNED.map(\n (verb) => ' ' + verb.name.padEnd(12) + verb.summary + ' (sub-phase ' + verb.phase + ')',\n ).join('\\n');\n return [\n 'pptx-studio ' + version(),\n '',\n 'Usage: pptx-studio <command> <deck.pptx> [options]',\n '',\n 'Commands:',\n ' inspect what is inside a package: parts, relationships, features',\n ' validate the must-not-break rules, with the part and the XPath',\n ' roundtrip read a deck, write it back, and prove nothing moved',\n ' render draw slides as SVG, with no browser and no LibreOffice',\n ' bisect narrow a broken deck to the change that breaks it',\n '',\n 'render options:',\n ' --slide <n> one slide, 1-based; every slide by default',\n ' --width <px> the SVG width attribute; the height follows the aspect ' +\n '(default ' +\n String(DEFAULT_WIDTH) +\n ')',\n ' --out <path> a directory, or a file when rendering one slide',\n ' --font-dir <d> look for fonts here first; repeatable',\n \" --no-system-fonts do not look in this platform's own font directories\",\n ' --no-text draw geometry only, and ask no font questions',\n ' --json what was drawn, and which face drew each typeface',\n ' --quiet no summary after writing',\n '',\n ' With no --out the markup goes to stdout, which is one slide worth doing.',\n ' In Node, `import { renderDeck } from \"@pptx-studio/cli\"` takes the five',\n ' drawing options above and defaults every one; --out, --json and --quiet are',\n \" this command's own.\",\n '',\n 'inspect options:',\n ' --json the census as JSON, for a script or for committing as a fixture',\n ' --parts include the per-part table',\n ' --namespaces include the namespace histogram',\n ' --top <n> rows per histogram before truncating (default 15)',\n ' --out <file> write to a file instead of stdout',\n '',\n 'validate options:',\n ' --json the report as JSON',\n ' --explain append the rationale for every rule that fired',\n ' --quiet fatal findings only',\n ' --out <file> write to a file instead of stdout',\n '',\n 'roundtrip options:',\n ' --json the comparison as JSON, with a digest per part',\n ' --quiet the differences only, without the tally',\n ' --write <file> also save the package that was written, to open in PowerPoint',\n ' --out <file> write the report to a file instead of stdout',\n '',\n 'bisect <deck.pptx> [broken.pptx]',\n ' With one deck the broken package is our own export of it; with two they',\n ' are the original and the broken package, in that order.',\n '',\n ' --oracle <name> validate (default), powerpoint, or command',\n ' --command <cmd> for --oracle command; {} becomes the candidate path',\n ' --max-runs <n> ceiling on oracle runs (default 2000)',\n ' --timeout <ms> per run, for the oracles that spawn something',\n ' --progress a line per oracle run; a bisection is not quick',\n ' --write <file> save the smallest package that still fails',\n ' --json the result as JSON',\n ' --quiet the changes that matter, without the tally',\n ' --out <file> write the report to a file instead of stdout',\n '',\n ' -h, --help this text',\n ' -v, --version print the version',\n '',\n 'Exit status is 1 when inspect finds a structural error, when validate finds',\n 'anything fatal, when roundtrip finds a difference, when render cannot draw,',\n 'or when bisect localizes one. 0 otherwise. Warnings and notes never fail a',\n 'command.',\n '',\n 'Not built yet:',\n planned,\n '',\n ].join('\\n');\n}\n\nexport interface Streams {\n readonly out: (text: string) => void;\n readonly err: (text: string) => void;\n}\n\nconst CONSOLE_STREAMS: Streams = {\n out: (text) => process.stdout.write(text),\n err: (text) => process.stderr.write(text),\n};\n\n/** Parse, dispatch, and return an exit code. Never calls `process.exit`. */\nexport function main(argv: readonly string[], streams: Streams = CONSOLE_STREAMS): number {\n let parsed;\n try {\n parsed = parseArgs({\n args: [...argv],\n allowPositionals: true,\n // `--no-text` and `--no-system-fonts` are the only way to spell turning a\n // defaulted-true flag off, and parseArgs rejects them without this.\n allowNegative: true,\n options: {\n json: { type: 'boolean', default: false },\n explain: { type: 'boolean', default: false },\n quiet: { type: 'boolean', default: false },\n parts: { type: 'boolean', default: false },\n namespaces: { type: 'boolean', default: false },\n top: { type: 'string' },\n out: { type: 'string' },\n write: { type: 'string' },\n oracle: { type: 'string' },\n slide: { type: 'string' },\n width: { type: 'string' },\n 'font-dir': { type: 'string', multiple: true },\n 'system-fonts': { type: 'boolean', default: true },\n text: { type: 'boolean', default: true },\n command: { type: 'string' },\n 'max-runs': { type: 'string' },\n timeout: { type: 'string' },\n progress: { type: 'boolean', default: false },\n help: { type: 'boolean', short: 'h', default: false },\n version: { type: 'boolean', short: 'v', default: false },\n },\n });\n } catch (error) {\n streams.err(describe(error) + '\\n\\n' + usage());\n return 2;\n }\n\n const { values, positionals } = parsed;\n if (values.version === true) {\n streams.out(version() + '\\n');\n return 0;\n }\n const command = positionals[0];\n if (values.help === true || command === undefined) {\n streams.out(usage());\n return command === undefined && values.help !== true ? 2 : 0;\n }\n\n const planned = PLANNED.find((verb) => verb.name === command);\n if (planned !== undefined) {\n streams.err(\n 'pptx-studio ' +\n command +\n ' is not built yet: it arrives with sub-phase ' +\n planned.phase +\n '.\\n' +\n ' ' +\n planned.summary +\n '\\n',\n );\n return 2;\n }\n\n if (\n command !== 'inspect' &&\n command !== 'validate' &&\n command !== 'roundtrip' &&\n command !== 'render' &&\n command !== 'bisect'\n ) {\n streams.err('unknown command: ' + command + '\\n\\n' + usage());\n return 2;\n }\n\n const file = positionals[1];\n if (file === undefined) {\n streams.err(command + ' needs a path to a .pptx\\n\\n' + usage());\n return 2;\n }\n\n if (command === 'bisect') {\n const oracle = values.oracle ?? BISECT_DEFAULTS.oracle;\n if (oracle !== 'validate' && oracle !== 'powerpoint' && oracle !== 'command') {\n streams.err('--oracle wants validate, powerpoint or command, got ' + oracle + '\\n');\n return 2;\n }\n if (oracle === 'command' && values.command === undefined) {\n streams.err('--oracle command needs --command \"<what to run>\"\\n');\n return 2;\n }\n const maxRuns = positiveInteger(values['max-runs'], BISECT_DEFAULTS.maxRuns);\n const timeout = positiveInteger(values.timeout, BISECT_DEFAULTS.timeout);\n if (maxRuns === null || timeout === null) {\n streams.err('--max-runs and --timeout want positive integers\\n');\n return 2;\n }\n\n const options: BisectOptions = {\n oracle,\n command: values.command ?? null,\n maxRuns,\n timeout,\n write: values.write ?? null,\n json: values.json === true,\n quiet: values.quiet === true,\n out: values.out ?? null,\n progress: values.progress === true,\n };\n try {\n return runBisect(file, positionals[2] ?? null, options, streams.out);\n } catch (error) {\n // The same three-way split `roundtrip` makes, plus one of its own: the\n // one-deck form exports the deck first, so the firewall can refuse before\n // there is anything to bisect.\n if (isValidateError(error)) {\n streams.err(\n 'pptx-studio: the export was refused, so there was no broken package to compare.\\n ' +\n error.message +\n '\\n',\n );\n } else if (isOpcError(error)) {\n streams.err('pptx-studio: ' + error.code + ': ' + error.message + '\\n');\n } else {\n streams.err('pptx-studio: ' + describe(error) + '\\n');\n }\n return 1;\n }\n }\n\n if (command === 'render') {\n const slide = values.slide === undefined ? null : Number.parseInt(values.slide, 10);\n if (slide !== null && (!Number.isFinite(slide) || slide < 1)) {\n streams.err('--slide wants a positive integer, got ' + String(values.slide) + '\\n');\n return 2;\n }\n const width = positiveInteger(values.width, DEFAULT_WIDTH);\n if (width === null) {\n streams.err('--width wants a positive integer, got ' + String(values.width) + '\\n');\n return 2;\n }\n const options: RenderOptions = {\n slide,\n width,\n out: values.out ?? null,\n fontDirs: values['font-dir'] ?? [],\n systemFonts: values['system-fonts'] !== false,\n text: values.text !== false,\n json: values.json === true,\n quiet: values.quiet === true,\n };\n try {\n return runRender(file, options, streams.out);\n } catch (error) {\n // A render fails for a reason the caller can act on - a font directory\n // that is not there, a typeface nothing can stand in for, a slide the\n // deck does not have - so the code is worth more than the sentence.\n if (isRenderError(error)) {\n streams.err('pptx-studio: ' + error.code + ': ' + error.message + '\\n');\n } else if (isOpcError(error)) {\n streams.err('pptx-studio: ' + error.code + ': ' + error.message + '\\n');\n } else {\n streams.err('pptx-studio: ' + describe(error) + '\\n');\n }\n return 1;\n }\n }\n\n if (command === 'roundtrip') {\n const options: RoundTripOptions = {\n json: values.json === true,\n quiet: values.quiet === true,\n out: values.out ?? null,\n write: values.write ?? null,\n };\n try {\n return runRoundTrip(file, options, streams.out);\n } catch (error) {\n // Three ways to fail and one exit code, so the message has to carry the\n // distinction. A package that will not open, an export the firewall\n // refused, and a comparison that found a difference are three different\n // pieces of work; a script only wants one bit, and a person wants to know\n // which of the three it was.\n if (isValidateError(error)) {\n streams.err(\n 'pptx-studio: the export was refused, so there was nothing to compare.\\n ' +\n error.message +\n '\\n',\n );\n } else if (isOpcError(error)) {\n streams.err('pptx-studio: ' + error.code + ': ' + error.message + '\\n');\n } else {\n streams.err('pptx-studio: ' + describe(error) + '\\n');\n }\n return 1;\n }\n }\n\n if (command === 'validate') {\n const options: ValidateOptions = {\n json: values.json === true,\n explain: values.explain === true,\n quiet: values.quiet === true,\n out: values.out ?? null,\n };\n try {\n return runValidate(file, options, streams.out);\n } catch (error) {\n // The same split `inspect` makes below. A package that will not open at\n // all is a different answer from a package with findings in it, and only\n // the second one is a report.\n if (isOpcError(error)) {\n streams.err('pptx-studio: ' + error.code + ': ' + error.message + '\\n');\n return 1;\n }\n streams.err('pptx-studio: ' + describe(error) + '\\n');\n return 1;\n }\n }\n\n const top = values.top === undefined ? INSPECT_DEFAULTS.top : Number.parseInt(values.top, 10);\n if (!Number.isFinite(top) || top < 1) {\n streams.err('--top wants a positive integer, got ' + String(values.top) + '\\n');\n return 2;\n }\n\n const options: InspectOptions = {\n json: values.json === true,\n parts: values.parts === true,\n namespaces: values.namespaces === true,\n top,\n out: values.out ?? null,\n };\n\n try {\n return runInspect(file, options, streams.out);\n } catch (error) {\n // A census does not refuse a broken deck; it refuses a file that is not a\n // package at all, and `opc` says which rule it broke. Reporting the code\n // matters more than the sentence - it is what a script can branch on.\n if (isOpcError(error)) {\n streams.err('pptx-studio: ' + error.code + ': ' + error.message + '\\n');\n return 1;\n }\n streams.err('pptx-studio: ' + describe(error) + '\\n');\n return 1;\n }\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** A numeric flag, or null when what was given is not one. */\nfunction positiveInteger(value: string | undefined, fallback: number): number | null {\n if (value === undefined) return fallback;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pptx-studio/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Command line tools for PPTX packages: render slides to SVG without a browser, inspect a deck, validate it, prove a round trip, and bisect the change that breaks it",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
"./package.json": "./package.json"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@pptx-studio/census": "^0.1.
|
|
55
|
-
"@pptx-studio/
|
|
56
|
-
"@pptx-studio/
|
|
57
|
-
"@pptx-studio/text": "^0.
|
|
58
|
-
"@pptx-studio/render-svg": "^0.
|
|
59
|
-
"@pptx-studio/validate": "^0.1.
|
|
60
|
-
"@pptx-studio/
|
|
61
|
-
"@pptx-studio/
|
|
54
|
+
"@pptx-studio/census": "^0.1.1",
|
|
55
|
+
"@pptx-studio/model": "^0.1.1",
|
|
56
|
+
"@pptx-studio/opc": "^0.1.1",
|
|
57
|
+
"@pptx-studio/text": "^0.2.0",
|
|
58
|
+
"@pptx-studio/render-svg": "^0.2.0",
|
|
59
|
+
"@pptx-studio/validate": "^0.1.1",
|
|
60
|
+
"@pptx-studio/xml": "^0.1.1",
|
|
61
|
+
"@pptx-studio/writer": "^0.1.1"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@arethetypeswrong/cli": "0.18.5",
|