@pptx-studio/validate 0.1.1 → 0.1.2
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 +12 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @pptx-studio/validate
|
|
2
2
|
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 88cdb45: V028 no longer mistakes the extent of a transform for an extension.
|
|
8
|
+
|
|
9
|
+
The rule holds `mc:AlternateContent` and every `ext` inside an `extLst` opaque, by local name so
|
|
10
|
+
that vocabularies never read are covered too. It matched any element spelled `ext`, and the
|
|
11
|
+
extent inside `a:xfrm` is spelled `ext` as well - so a placeholder given a transform of its own,
|
|
12
|
+
which is what PowerPoint writes when one is dragged, was refused as a rebuilt extension. An `ext`
|
|
13
|
+
is now an extension only under an `extLst`.
|
|
14
|
+
|
|
3
15
|
## 0.1.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1823,9 +1823,9 @@ function sameBytes(a, b) {
|
|
|
1823
1823
|
for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;
|
|
1824
1824
|
return true;
|
|
1825
1825
|
}
|
|
1826
|
-
/**
|
|
1826
|
+
/** The containers held opaque, found by local name so that vocabularies never read are covered too. */
|
|
1827
1827
|
function isOpaqueContainer(element) {
|
|
1828
|
-
return element.local === "AlternateContent" || element.local === "ext";
|
|
1828
|
+
return element.local === "AlternateContent" || element.local === "ext" && element.parent?.local === "extLst";
|
|
1829
1829
|
}
|
|
1830
1830
|
/** Every opaque container in a document, as its exact source text. */
|
|
1831
1831
|
function opaqueSources(document) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#documents","#baselineDocuments","#parts","#parse","#contentTypesDocument","forEachElement"],"sources":["../src/errors.ts","../src/rules/rules.ts","../src/report/report.ts","../src/report/location.ts","../src/context.ts","../src/rels.ts","../src/rules/package.ts","../src/rules/relationships.ts","../src/rules/order.ts","../src/rules/required.ts","../src/rules/id.ts","../src/rules/refusal.ts","../src/rules/preservation.ts","../src/validate.ts"],"sourcesContent":["/**\n * The single error type this package throws.\n *\n * Same invariant as `@pptx-studio/opc` and `@pptx-studio/xml`: **every failure\n * path throws a `ValidateError` and nothing else.**\n *\n * There is a second thing worth saying here, because this package is the one\n * where the distinction matters most. A *finding* is not an error. A finding is\n * the normal output of this package - it says a rule was broken, names the part\n * and the element, and is data a caller can render, sort or ignore. An error is\n * thrown only when validation itself could not be carried out, or when a caller\n * asked for bytes and the report says they must not have them.\n *\n * Getting that split wrong is how a validator becomes something people disable.\n * If every broken rule were an exception, the only way to see the second\n * problem would be to fix the first, and a caller with a deck that breaks nine\n * rules would learn about them one export at a time.\n */\n\n/**\n * Machine-readable failure reasons.\n *\n * Deliberately few. Almost everything this package has to say is a finding.\n */\nexport const VALIDATE_ERROR_CODES = [\n /**\n * The report carries at least one fatal finding this session introduced, and\n * a caller asked for the bytes anyway.\n *\n * The one that stops a repair prompt reaching a user. `detail.report` carries\n * the whole report, so the caller does not have to re-run validation to find\n * out what was wrong.\n */\n 'ERR_VALIDATION_FAILED',\n /**\n * Validation could not be carried out at all.\n *\n * Not \"the package is invalid\" - \"the package could not be read far enough to\n * ask the questions\". A `[Content_Types].xml` that will not parse is this,\n * because without it no part has a content type and there is nothing to\n * validate against.\n */\n 'ERR_UNVALIDATABLE',\n /** A caller named a rule id that does not exist. */\n 'ERR_UNKNOWN_RULE',\n] as const;\n\nexport type ValidateErrorCode = (typeof VALIDATE_ERROR_CODES)[number];\n\nexport interface ValidateErrorDetail {\n /** The part the failure is about, if it is about one. */\n readonly part?: string;\n /** The rule id a caller got wrong, for `ERR_UNKNOWN_RULE`. */\n readonly rule?: string;\n /**\n * The full report, for `ERR_VALIDATION_FAILED`.\n *\n * Typed `unknown` rather than `Report` on purpose: `report.ts` imports this\n * module for the error, so typing this field would make the two circular.\n * Callers narrow it with `isReport`.\n */\n readonly report?: unknown;\n}\n\nexport class ValidateError extends Error {\n readonly code: ValidateErrorCode;\n readonly detail: ValidateErrorDetail;\n\n constructor(code: ValidateErrorCode, message: string, detail: ValidateErrorDetail = {}) {\n super(message);\n this.name = 'ValidateError';\n this.code = code;\n this.detail = detail;\n }\n}\n\nexport function isValidateError(value: unknown): value is ValidateError {\n return value instanceof ValidateError;\n}\n","/**\n * The twenty-nine rules, and the evidence for each.\n *\n * ## Why a table and not twenty-nine functions\n *\n * The functions are in the files beside this one. What lives here is the part a\n * person reads: what each rule claims, how sure we are, and *how we know*. A\n * validator whose rules exist only as code is a validator nobody can audit, and\n * this one has to be audited, because roughly half of it enforces things no\n * schema says.\n *\n * That is the fact that shapes the whole package. ECMA-376 is a description of\n * a file format; PowerPoint is an implementation that refuses files the\n * description permits. Sub-phase 0.7 and the corpus bisections in\n * `tools/corpus/ROSTER.md` found nineteen such refusals by building a package\n * with one change in it and watching PowerPoint decline to open it - no\n * diagnostic, no log, no part named, just \"PowerPoint could not open the file\"\n * or `0x80070570`. Every rule below whose `evidence` says `measured` came from\n * that loop and from nowhere else.\n *\n * So each rule carries three things beyond its check:\n *\n * - `evidence` - `schema` (ECMA-376 says so), `measured` (we watched PowerPoint\n * refuse it), or `both`.\n * - `why` - the sentence that justifies the rule to somebody who is about to\n * delete it because it fired on their file.\n * - `severity` - `fatal` refuses an export; `warning` is reported and does not.\n *\n * ## On being wrong in the safe direction\n *\n * A false positive here blocks an export a user wanted. A false negative hands\n * them a file PowerPoint will not open, with no way to find out why. Those are\n * not symmetric, but the first is not free either - a validator that fires on\n * good files gets turned off, and then it catches nothing.\n *\n * The resolution is `origin`, which lives on the finding rather than here: a\n * fatal a caller *introduced* refuses the export, and the identical fatal that\n * was already in the file when it was opened is reported and does not. That is\n * the same split `PartStore.write` already makes for dangling relationships,\n * and for the same reason - refusing to re-export a file we did not break makes\n * the file unopenable in this editor and does not fix anything.\n */\n\nexport type RuleCategory =\n 'package' | 'relationships' | 'order' | 'required' | 'ids' | 'refused' | 'preservation';\n\nexport type Severity = 'fatal' | 'warning';\n\n/** Where the rule comes from. See the header. */\nexport type Evidence = 'schema' | 'measured' | 'both';\n\nexport interface Rule {\n readonly id: RuleId;\n readonly category: RuleCategory;\n readonly severity: Severity;\n readonly evidence: Evidence;\n /** One line, imperative, in the voice of the thing that must be true. */\n readonly title: string;\n /** Why the rule exists, for whoever is about to argue with it. */\n readonly why: string;\n /**\n * True when the rule needs the package as it was opened as well as the\n * package about to be written.\n *\n * Six rules do. They are skipped rather than passed when no baseline is\n * given, and the report says so - a preservation rule that silently reports\n * nothing because it had nothing to compare against is worse than one that\n * did not run, because it looks like a pass.\n */\n readonly needsBaseline?: true;\n}\n\n/**\n * The shape each entry is checked against.\n *\n * `RULES` is `as const satisfies readonly RuleShape[]` rather than typed\n * `readonly Rule[]`, so that `RuleId` below can be the union of the twenty-nine\n * literal ids written here instead of `string`. Annotating the array would\n * widen `id`, and then a caller could ask for a rule that does not exist and be\n * told so only at run time.\n */\ninterface RuleShape {\n readonly id: string;\n readonly category: RuleCategory;\n readonly severity: Severity;\n readonly evidence: Evidence;\n readonly title: string;\n readonly why: string;\n readonly needsBaseline?: true;\n}\n\nexport const RULES = [\n // --- package ------------------------------------------------------------\n\n {\n id: 'V001',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'every part resolves to a content type',\n why:\n 'OPC has no default type. A part whose extension matches no `Default` and ' +\n 'which carries no `Override` has no type at all, and a consumer has no way ' +\n 'to know what it is holding. PowerPoint refuses such a package outright.',\n },\n {\n id: 'V002',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'the content-type map is internally consistent',\n why:\n 'Every `Override` names a part that exists; no extension is declared ' +\n '`Default` twice; no part is `Override`-ed twice. And the one Office ' +\n 'omission that is famous for it: whenever any `.fntdata` part exists there ' +\n 'must be a `<Default Extension=\"fntdata\" ContentType=\"application/x-fontdata\"/>`. ' +\n 'Leaving it out is the canonical \"PowerPoint found a problem with content\" ' +\n 'bug and it is what sub-phase 8.7 exists to get right.',\n },\n {\n id: 'V003',\n category: 'package',\n severity: 'fatal',\n evidence: 'schema',\n title: 'the archive carries no directory entries and no ZIP64 record',\n why:\n 'A directory entry is not a part - no OPC part name may end in a slash - so ' +\n 'writing one puts a thing in the package that nothing can name. ZIP64 is ' +\n 'refused for a narrower reason: PowerPoint reads it, but our writer emits ' +\n 'ZIP32 only, so a ZIP64 record in something we produced means a length ' +\n 'field went somewhere it should not have. Both are about what *we* hand ' +\n 'over; a package that arrives with either is reported and not refused.',\n },\n {\n id: 'V004',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'part names are ASCII, well formed, and free of pointless percent-escapes',\n why:\n 'The OPC grammar, plus the one thing it does not say. RFC 3986 §6.2.2.2 ' +\n 'normalisation is enforced by PowerPoint rather than merely recommended: a ' +\n 'percent-escape of an *unreserved* character is a whole-package refusal ' +\n 'with `0x808D1005`. Measured nine for nine on one-name packages - `%2D`, ' +\n '`%41`, `%5F` and `%7E` refused; `%20`, `%23`, `%24`, `%2C` and `%3A` open. ' +\n '`@pptx-studio/opc` reports this as a warning (`M1.8`) because it must open ' +\n 'what it is given; here it is fatal, because we are about to write it.',\n },\n {\n id: 'V005',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'there is exactly one main presentation part, of a matching content type',\n why:\n '`_rels/.rels` must carry exactly one `officeDocument` relationship and it ' +\n 'must resolve to a part whose content type is one of the four PresentationML ' +\n 'main-part types. And the pairing PowerPoint enforces outside the schema: it ' +\n 'checks the *file extension* against that content type and refuses the pair ' +\n 'when they disagree, which is why a macro-enabled deck has to be written ' +\n '`.pptm`. `a32-macros` is the corpus deck that measured it.',\n },\n\n // --- relationships ------------------------------------------------------\n\n {\n id: 'V006',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'both',\n title: 'every relationship reference resolves in its own part’s `.rels`',\n why:\n '`r:id`, `r:embed`, `r:link`, `r:pict`, `r:dm`, `r:lo`, `r:qs`, `r:cs` and ' +\n 'every other attribute in the relationship namespace. Relationship ids are ' +\n '`xsd:ID` scoped to one `.rels` part, so the lookup is always against the ' +\n 'referring part’s own collection and never against a global registry - a ' +\n 'global one is not a shortcut, it is a bug. A dangling reference is fatal ' +\n 'where an orphan relationship is harmless, which is the asymmetry that ' +\n 'decides which direction media garbage collection may be aggressive in.',\n },\n {\n id: 'V007',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'schema',\n title: 'relationship ids are unique within a `.rels` and match the `xsd:ID` grammar',\n why:\n '`Relationship/@Id` is `xsd:ID`: an XML Name, unique in its document. Two ' +\n 'relationships sharing an id in one `.rels` makes every reference to it ' +\n 'ambiguous, and which one a consumer picks is not defined anywhere.',\n },\n {\n id: 'V008',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'both',\n title: 'internal targets resolve inside the package, relative to the source part’s folder',\n why:\n 'A target is resolved against the folder of the part that *owns the `.rels`*, ' +\n 'not against the package root and not against the `.rels` part’s own folder. ' +\n 'Getting that wrong moves every relative target one directory up and is the ' +\n 'classic reason a rebuilt deck loses all its images at once. `TargetMode=' +\n '\"External\"` is passed through untouched and not resolved at all.',\n },\n {\n id: 'V009',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'measured',\n title: 'the relationship edges a part must have, and the ones it must not',\n why:\n 'Four findings, none of them in any schema, all found by bisection. ' +\n '(1) A slide needs **exactly one** `slideLayout` relationship resolving to a ' +\n 'layout part - zero, two, one pointing at a master and one pointing at a ' +\n 'missing part were each built as a single change and each refused; the ' +\n 'binding lives only in the rels part, which is why \"change layout\" is a ' +\n 'relationship rewrite. (2) A layout needs exactly one `slideMaster`. ' +\n '(3) A `cx:chartSpace` part with no `.rels` of its own is a whole-package ' +\n 'refusal - it needs a `chartStyle` and a `chartColorStyle`, where the classic ' +\n '`c:chartSpace` needs neither. (4) A media part may not be both a media ' +\n 'object’s target and a transition’s `p:snd`; two copies of the same bytes ' +\n 'open, one shared copy does not.',\n },\n\n // --- element order ------------------------------------------------------\n\n {\n id: 'V010',\n category: 'order',\n severity: 'fatal',\n evidence: 'both',\n title: 'children appear in schema-sequence order',\n why:\n 'OOXML complex types are `xsd:sequence` almost everywhere, and PowerPoint ' +\n 'enforces it. Microsoft’s own Open XML SDK shipped a regression that merely ' +\n 'swapped two elements in `slideMaster1.xml` and PowerPoint refused the file. ' +\n 'The ranks come from `@pptx-studio/xml`’s table, generated from the ECMA-376 ' +\n 'Transitional schemas and checked against 194 148 elements PowerPoint wrote. ' +\n 'This rule also covers the two the plan calls out by name, because the table ' +\n 'already ranks them: `a:rPr` before `a:t`, and `a:endParaRPr` last in `a:p`.',\n },\n {\n id: 'V011',\n category: 'order',\n severity: 'fatal',\n evidence: 'schema',\n title: '`extLst` is last among its siblings, and every `a:ext` carries a `@uri`',\n why:\n 'Its own rule rather than a case of `V010`, because it has to hold in the ' +\n 'places the generated table cannot rank - extension markup, `xsd:any` ' +\n 'wildcards, and the vocabularies outside the four schemas we generate from. ' +\n '`extLst` is always last in every type that has one, and an `a:ext` without ' +\n 'a `@uri` is an extension nobody can identify, which makes it unpreservable: ' +\n 'the whole `extLst` contract is \"carry it through untouched, keyed by uri\".',\n },\n {\n id: 'V012',\n category: 'order',\n severity: 'fatal',\n evidence: 'both',\n title: 'no child appears in a parent whose content model has no place for it',\n why:\n 'Ordering catches a child in the wrong *position*; this catches one in the ' +\n 'wrong *parent*, which the ordering rule cannot see because an unrankable ' +\n 'child is skipped there rather than reported. The case that made it a rule ' +\n 'is measured: `a:ahXY` or `a:cxn` as a direct child of `a:custGeom`, without ' +\n 'its `a:ahLst`/`a:cxnLst` wrapper, is a whole-package refusal. Only parents ' +\n 'the table knows and whose model has no `xsd:any` are checked, and markup in ' +\n 'a namespace the table does not cover is left alone.',\n },\n\n // --- required -----------------------------------------------------------\n\n {\n id: 'V013',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:presentation` carries `p:notesSz`',\n why:\n 'The asymmetry that catches people: in `CT_Presentation`, `p:sldSz` is ' +\n '`[0..1]` and `p:notesSz` is `[1..1]`. A generator that treats the two the ' +\n 'same way, or that omits both because the deck has no notes, writes a ' +\n 'presentation part that is missing a required child.',\n },\n {\n id: 'V014',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:clrMap` carries all twelve attributes',\n why:\n '`CT_ColorMapping` has twelve attributes - `bg1`, `tx1`, `bg2`, `tx2`, ' +\n '`accent1`…`accent6`, `hlink`, `folHlink` - and every one is required. There ' +\n 'is no default and no partial map: eleven of twelve is not a map with one ' +\n 'slot missing, it is an invalid element. This is also the element that ' +\n 'decides what `bg1` and `tx1` resolve to, so a wrong one is a deck that ' +\n 'renders in the wrong colours everywhere at once.',\n },\n {\n id: 'V015',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:spTree` begins with `p:nvGrpSpPr` then `p:grpSpPr`',\n why:\n 'A shape tree is a group shape, and `CT_GroupShape` requires both of them ' +\n 'first, in that order, before any child shape. An empty slide still has ' +\n 'them. This is separate from `V010` because the failure is a missing ' +\n 'required child rather than a misordered optional one, and the two need ' +\n 'different messages: \"add this\" against \"move this\".',\n },\n {\n id: 'V016',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: 'every text body has `a:bodyPr` and at least one `a:p`',\n why:\n '`CT_TextBody` is `bodyPr` then optional `lstStyle` then `a:p` at ' +\n '`[1..unbounded]`. A shape whose text was deleted down to nothing is the ' +\n 'way this gets broken in an editor: the last paragraph goes, and what is ' +\n 'left is a `p:txBody` with no `a:p` in it. An empty paragraph is not the ' +\n 'same as no paragraph, and `a:endParaRPr` is where its height comes from.',\n },\n {\n id: 'V017',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:graphicFrame` carries `p:xfrm` and `a:graphic`',\n why:\n 'And note the namespace: it is `p:xfrm`, PresentationML, not the `a:xfrm` ' +\n 'that every other shape uses. A graphic frame has no placeholder-inherited ' +\n 'geometry path, so this is also the reason sub-phase 7.4 gives a rebound ' +\n 'chart or table a *copy* of the target layout’s transform instead of ' +\n 'deleting its own the way it does for every other shape - delete it there ' +\n 'and the frame collapses to zero size.',\n },\n\n // --- ids ----------------------------------------------------------------\n\n {\n id: 'V018',\n category: 'ids',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:sldId/@id` is 256…2147483647 and unique',\n why:\n '`ST_SlideId` is not zero-based and not unbounded. The floor of 256 is the ' +\n 'part people get wrong, because nothing about a first slide suggests its id ' +\n 'should start there. Four id spaces exist in a presentation and they are not ' +\n 'one allocator; this is the first of them.',\n },\n {\n id: 'V019',\n category: 'ids',\n severity: 'fatal',\n evidence: 'both',\n title: 'master and layout ids are ≥ 2147483648 and unique **across both lists**',\n why:\n '`ST_SlideMasterId` and `ST_SlideLayoutId` are both \"2147483648 and up\" and ' +\n 'no schema says they may not overlap. PowerPoint allocates them from one ' +\n 'running counter - master, its layouts, next master, its layouts - and ' +\n 'refuses a package that does not. Found by bisection when `a12-masters` ' +\n 'would not open: two counters are indistinguishable from correct with one ' +\n 'master and collide on the second, so **every** two-master package was ' +\n 'refused.',\n },\n {\n id: 'V020',\n category: 'ids',\n severity: 'fatal',\n evidence: 'both',\n title: '`p:cNvPr/@id` is unique within its part and ≤ 2147483647',\n why:\n 'Unique *within a part*, and free to repeat across parts - a shape id is not ' +\n 'a document-wide identity and treating it as one is how a duplicate-slide ' +\n 'implementation ends up renumbering things it should not. The range is ' +\n 'measured rather than read: `ST_DrawingElementId` is `xsd:unsignedInt`, but ' +\n 'every value from 0 to 2147483647 opens, 2147483648…4294967294 are ' +\n 'whole-package refusals, and 4294967295 opens - PowerPoint reads the ' +\n 'attribute as a signed 32-bit integer and keeps `0xFFFFFFFF` as a sentinel ' +\n 'it renumbers away on save. `a39-large-ids` is the corpus deck.',\n },\n {\n id: 'V021',\n category: 'ids',\n severity: 'warning',\n evidence: 'schema',\n title: 'a slide placeholder’s `(type, idx)` has a counterpart in its layout',\n why:\n 'A `p:ph` that matches nothing in the layout inherits nothing: no geometry, ' +\n 'no text style, no prompt. PowerPoint opens the file and draws the shape at ' +\n 'whatever it can work out, which is why this is a warning and not fatal - ' +\n 'the deck is not refused, it is silently wrong. Matching follows the five ' +\n 'tiers sub-phase 7.1 hardens, and the asymmetry that matters is checked ' +\n 'here too: slide→layout matches on `(type, idx)` where layout→master ' +\n 'matches on **type only**.',\n },\n\n // --- refused ------------------------------------------------------------\n\n {\n id: 'V022',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: '`p:ph/@type` is not `hdr` or `sldImg` outside a notes or handout part',\n why:\n 'A whole-package refusal, on a slide layout and on a slide alike, either one ' +\n 'alone with no other change. The other seven content types were built as ' +\n 'one-type packages in the same bisection and every one opens: `obj`, ' +\n '`chart`, `tbl`, `clipArt`, `dgm`, `media`, `pic`. Nothing in the schema ' +\n 'says so - `CT_Placeholder` is one complex type shared by masters, layouts, ' +\n 'slides, notes slides and handout masters, and `ST_PlaceholderType` is one ' +\n 'enumeration holding all sixteen values. The restriction is real and ' +\n 'unwritten: those two belong to the notes and handout families.',\n },\n {\n id: 'V023',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: 'every geometry guide named is a guide that is defined',\n why:\n 'A whole-package refusal, not a repair and not a dropped shape. It applies ' +\n 'both to an `a:gd` formula naming an adjust value no `a:avLst` defines and ' +\n 'to an `a:pt` coordinate naming a guide no `a:gdLst` defines. ' +\n '`ST_GeomGuideName` is an unconstrained token, so this is schema-legal ' +\n 'markup refused for a reason no schema states - and it is the rule that ' +\n 'sub-phase 2.5 needs, because dragging an adjust handle is exactly the ' +\n 'operation that can write a formula referring to a guide that is no longer ' +\n 'there.',\n },\n {\n id: 'V024',\n category: 'refused',\n severity: 'fatal',\n evidence: 'both',\n title: '`c:tx` holds `c:strRef` or `c:v`, never `c:strLit`',\n why:\n '`CT_SerTx` is a choice of exactly those two. The trap is that `c:cat` and ' +\n '`c:val`, two elements away in the same series, both accept the literal ' +\n 'forms - so the markup looks like something that ought to work, and it is a ' +\n 'whole-package refusal.',\n },\n {\n id: 'V025',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: 'no `p:control`',\n why:\n 'A whole-package refusal in all eight forms tried: bare, name-only, with and ' +\n 'without `r:id`, with a `p:pic` preview, with an ActiveX part and its `.bin`, ' +\n 'and inside a macro-enabled package. An empty `p:controls` is accepted, ' +\n 'which places the refusal precisely on the child element. We do not author ' +\n 'ActiveX controls and never will; the rule exists so that a file that has ' +\n 'one is not handed back with it re-serialised into a form PowerPoint likes ' +\n 'less than the original.',\n },\n {\n id: 'V026',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: 'a `cs:chartStyle` carries all thirty-one of its entries',\n why:\n 'Four entries refused; thirty-one opened. And the shape of the finding is ' +\n 'the interesting half: a chart with **no** chart-style relationship at all is ' +\n 'fine, so this is not \"the part is required\" - it is \"if the part exists it ' +\n 'must be complete\". A subset is worse than an absence, which is the opposite ' +\n 'of what a partial-styling model would predict.',\n },\n\n // --- preservation -------------------------------------------------------\n\n {\n id: 'V027',\n category: 'preservation',\n severity: 'fatal',\n evidence: 'schema',\n needsBaseline: true,\n title: 'a part nobody edited comes back out byte-for-byte',\n why:\n 'The load-bearing one, and the reason the architecture is what it is. ' +\n 'Preserving charts, SmartArt, animations, OLE and macros is unachievable in ' +\n 'any design where the writer has to *understand* a feature to emit it, so ' +\n 'preservation is the default state rather than a feature - and this rule is ' +\n 'where that stops being an intention. `ppt/embeddings/*.bin` is called out ' +\n 'inside it: those are OLE2/CFB compound files and any rewrite of one is a ' +\n 'guaranteed repair prompt.',\n },\n {\n id: 'V028',\n category: 'preservation',\n severity: 'fatal',\n evidence: 'schema',\n needsBaseline: true,\n title: 'no `mc:AlternateContent` branch and no `extLst` was rebuilt',\n why:\n 'Two things we hold opaque, for one reason: we do not know what is in them. ' +\n 'An `mc:AlternateContent` branch we do not understand must arrive and leave ' +\n 'identical, because `mc:Choice/@Requires` names a *prefix* and rewriting the ' +\n 'branch is how ignorable extension markup becomes a hard error. An `extLst` ' +\n 'is an ordered list keyed by `@uri` and never a typed model that is rebuilt ' +\n 'from fields - `a34-extlst` measured that PowerPoint carries an unknown ' +\n '`a:ext/@uri` through untouched, so anything we drop there is something the ' +\n 'file would otherwise have kept forever.',\n },\n {\n id: 'V029',\n category: 'preservation',\n severity: 'fatal',\n evidence: 'both',\n needsBaseline: true,\n title: 'text and field identity survive: `xml:space`, `a:fld/@id`, cached field text',\n why:\n 'Three small things that are each silently destructive. An `a:t` with ' +\n 'leading or trailing whitespace needs `xml:space=\"preserve\"` if it was ' +\n 'written with it, because dropping the attribute changes what the text *is*. ' +\n '`a:fld/@id` is a required `ST_Guid` and regenerating one can make PowerPoint ' +\n 'repair the file. And a field’s cached `a:t` is the only thing that renders ' +\n 'when we cannot evaluate the field ourselves, so discarding it turns a date ' +\n 'placeholder into an empty box on every consumer that is not PowerPoint.',\n },\n] as const satisfies readonly RuleShape[];\n\nexport type RuleId = (typeof RULES)[number]['id'];\n\nconst BY_ID = new Map<string, Rule>(RULES.map((rule) => [rule.id, rule as Rule]));\n\nexport function ruleById(id: string): Rule | undefined {\n return BY_ID.get(id);\n}\n\nexport const RULE_IDS: readonly RuleId[] = RULES.map((rule) => rule.id);\n\n/** Rules that need the package as it was opened. See `Rule.needsBaseline`. */\nexport const BASELINE_RULES: readonly RuleId[] = RULES.filter(\n (rule) => 'needsBaseline' in rule,\n).map((rule) => rule.id);\n","import type { Location } from './location.js';\nimport { ruleById, type RuleCategory, type RuleId, type Severity } from '../rules/rules.js';\n\n/**\n * What validation produces.\n *\n * ## Origin, and why it is computed rather than guessed\n *\n * The hardest question this package has to answer is not \"is this file valid\".\n * It is **\"did we break it\"**, and those are different questions with different\n * consequences. A fatal finding in a deck the user imported ten seconds ago is\n * information; the same finding in a deck they just edited is a bug in us, and\n * handing over the bytes would give them a repair prompt with no explanation.\n *\n * Refusing both would be the strict-looking choice and it is the wrong one. It\n * would mean that a deck with one pre-existing defect - a dangling image\n * relationship, say, which PowerPoint tolerates and which is common in files\n * that have been through three other tools - could be opened in this editor and\n * never saved again. The editor would be refusing to give the user back their\n * own file over a problem it did not cause and cannot fix. `PartStore.write`\n * already made exactly this call for dangling relationships, and this is the\n * same call generalised to all twenty-nine rules.\n *\n * So `origin` is not a per-rule judgement call. It is computed by running the\n * rules a second time against the package **as it was opened** and differencing\n * the two reports: a finding that is in both is `inherited`, one that is only in\n * the new report is `introduced`. That is exact, it needs no rule to reason\n * about history, and it cannot drift from what the rules actually do.\n *\n * The second pass only happens when the first found something fatal, so a clean\n * export - the overwhelmingly common case - pays nothing for it.\n */\n\nexport type Origin =\n /** The finding is in the package we are about to write and was not in the original. */\n | 'introduced'\n /** The finding was already there when the package was opened. */\n | 'inherited'\n /** No baseline was supplied, so the question was not asked. */\n | 'unknown';\n\nexport interface Finding {\n readonly rule: RuleId;\n readonly severity: Severity;\n readonly category: RuleCategory;\n readonly where: Location;\n /**\n * What is wrong, in one sentence, naming the values involved.\n *\n * Written to be read on its own: a message that says \"invalid id\" and leaves\n * the reader to go and look is a message that costs more than it saves.\n */\n readonly message: string;\n readonly origin: Origin;\n}\n\n/** A rule that did not run, and why. Never silent - see `Report.skipped`. */\nexport interface SkippedRule {\n readonly rule: RuleId;\n readonly why: string;\n}\n\n/** Something that could not be read. Not a rule violation; a gap in coverage. */\nexport interface ReadProblem {\n readonly part: string;\n readonly message: string;\n}\n\nexport interface Report {\n /** Sorted: fatal before warning, then by part, then by offset. */\n readonly findings: readonly Finding[];\n /** Rules that ran. */\n readonly checked: readonly RuleId[];\n /**\n * Rules that did not run, and why.\n *\n * Present so that a report can never quietly mean less than it looks like it\n * means. Six rules need the package as it was opened; asked to validate a\n * package with no baseline they report nothing, and \"reported nothing\" and\n * \"found nothing\" are the same shape on a screen and opposite in meaning.\n */\n readonly skipped: readonly SkippedRule[];\n /** Parts that could not be read, and the rules that therefore did not see them. */\n readonly problems: readonly ReadProblem[];\n /** Fatal findings this session introduced. The number that refuses an export. */\n readonly blocking: number;\n /** True when nothing blocking was found. Not the same as \"no findings\". */\n readonly ok: boolean;\n}\n\n/** Fatal, then warning; then by part; then by offset; then by rule. */\nfunction compareFindings(a: Finding, b: Finding): number {\n if (a.severity !== b.severity) return a.severity === 'fatal' ? -1 : 1;\n if (a.where.part !== b.where.part) return a.where.part.localeCompare(b.where.part);\n const offsetA = a.where.offset ?? -1;\n const offsetB = b.where.offset ?? -1;\n if (offsetA !== offsetB) return offsetA - offsetB;\n return a.rule.localeCompare(b.rule);\n}\n\n/**\n * The key two reports are differenced on.\n *\n * Includes the message, because the message carries the instance - the id that\n * collided, the guide that was not defined. Two findings of the same rule at\n * the same place with different values are different findings, and treating\n * them as one would let an introduced defect hide behind an inherited one.\n */\nexport function findingKey(finding: Finding): string {\n return [finding.rule, finding.where.part, finding.where.xpath ?? '', finding.message].join(\n '\\u0000',\n );\n}\n\nexport function buildReport(input: {\n readonly findings: readonly Finding[];\n readonly checked: readonly RuleId[];\n readonly skipped: readonly SkippedRule[];\n readonly problems: readonly ReadProblem[];\n}): Report {\n const findings = [...input.findings].sort(compareFindings);\n const blocking = findings.filter(\n (finding) => finding.severity === 'fatal' && finding.origin !== 'inherited',\n ).length;\n return {\n findings,\n checked: input.checked,\n skipped: input.skipped,\n problems: input.problems,\n blocking,\n ok: blocking === 0,\n };\n}\n\nexport function isReport(value: unknown): value is Report {\n return (\n typeof value === 'object' &&\n value !== null &&\n Array.isArray((value as Report).findings) &&\n typeof (value as Report).blocking === 'number'\n );\n}\n\nexport interface FormatOptions {\n /** Include `inherited` findings. Default true. */\n readonly inherited?: boolean;\n /** Include warnings. Default true. */\n readonly warnings?: boolean;\n /** Append each rule's `why`, once per rule. Default false. */\n readonly explain?: boolean;\n}\n\n/**\n * A report as text.\n *\n * Grouped by part rather than by rule, because the question a reader has is\n * \"what is wrong with this file\", and a file is a set of parts. Grouping by\n * rule is the right shape for the corpus gate and the wrong one here.\n */\nexport function formatReport(report: Report, options: FormatOptions = {}): string {\n const showInherited = options.inherited ?? true;\n const showWarnings = options.warnings ?? true;\n\n const shown = report.findings.filter(\n (finding) =>\n (showInherited || finding.origin !== 'inherited') &&\n (showWarnings || finding.severity === 'fatal'),\n );\n\n const lines: string[] = [];\n if (shown.length === 0) {\n // 'nothing was found' and 'nothing survived the filter' are different\n // sentences, and a reader who asked to hide inherited findings has to be\n // able to tell which one they are looking at.\n lines.push(report.findings.length === 0 ? 'no findings' : 'no findings shown');\n } else {\n const byPart = new Map<string, Finding[]>();\n for (const finding of shown) {\n const bucket = byPart.get(finding.where.part);\n if (bucket) bucket.push(finding);\n else byPart.set(finding.where.part, [finding]);\n }\n for (const [part, findings] of byPart) {\n lines.push('');\n lines.push(' ' + (part === '/' ? '(package)' : part));\n for (const finding of findings) {\n const tag =\n finding.severity === 'fatal'\n ? finding.origin === 'inherited'\n ? 'fatal (already there)'\n : 'fatal'\n : 'warning';\n lines.push(' ' + finding.rule + ' ' + tag);\n if (finding.where.xpath !== null) lines.push(' ' + finding.where.xpath);\n lines.push(' ' + finding.message);\n }\n }\n }\n\n for (const problem of report.problems) {\n lines.push('');\n lines.push(' ' + problem.part + ' could not be read: ' + problem.message);\n }\n for (const skipped of report.skipped) {\n lines.push('');\n lines.push(' ' + skipped.rule + ' did not run: ' + skipped.why);\n }\n\n if (options.explain === true) {\n const seen = new Set<RuleId>();\n for (const finding of shown) {\n if (seen.has(finding.rule)) continue;\n seen.add(finding.rule);\n const rule = ruleById(finding.rule);\n if (rule === undefined) continue;\n lines.push('');\n lines.push(' ' + rule.id + ' - ' + rule.title);\n lines.push(' ' + rule.why);\n }\n }\n\n lines.push('');\n lines.push(\n 'validate: ' +\n String(report.checked.length) +\n ' rule(s), ' +\n String(report.findings.length) +\n ' finding(s), ' +\n String(report.blocking) +\n ' blocking',\n );\n return lines.join('\\n');\n}\n","import {\n attribute,\n type XAttribute,\n type XDocument,\n type XElement,\n type XNode,\n} from '@pptx-studio/xml';\n\n/**\n * Where a finding is, in a form a person can act on.\n *\n * ## Why an XPath and not a byte offset\n *\n * Both, actually - the offset is on the finding too, because it is what\n * `cli bisect` needs in sub-phase 1.5 and what a diff viewer can highlight. But\n * the offset is useless to a human: it names a position in a file that is\n * usually one line long and often two megabytes wide, and it stops being true\n * the moment anything above it changes.\n *\n * An XPath survives editing, survives reformatting, and can be pasted into\n * every XML tool there is. More to the point, it is the only form in which\n * a report about eleven parts is *readable* - `ppt/slides/slide3.xml` at\n * `/p:sld/p:cSld/p:spTree/p:sp[2]/p:nvSpPr/p:cNvPr/@id` says what is wrong in\n * one line, and byte 41 207 does not.\n *\n * ## Prefixes are the document's own, always\n *\n * The path is built from `qname` as written in the file - not from a canonical\n * prefix table, and not from the namespace URI. If a part spells the\n * PresentationML namespace `pp:` instead of `p:`, the path says `pp:`, because\n * the point of the path is that a reader can find the element in the file in\n * front of them. A canonicalised path would be *more correct* as an XPath\n * expression and less useful as a location, and this is a diagnostic rather\n * than a query.\n *\n * The same choice is made everywhere in this project for the same reason, and\n * it is not stylistic: `mc:Ignorable` and `mc:Choice/@Requires` hold prefixes\n * rather than URIs, so a prefix is load-bearing data in OOXML and inventing one\n * is never a neutral act.\n *\n * ## The positional predicate\n *\n * `[n]` is emitted only where it disambiguates - that is, when the element has\n * a sibling of the same `qname`. `/p:sld/p:cSld/p:spTree/p:sp[2]` is exact;\n * `/p:sld[1]/p:cSld[1]/p:spTree[1]` is noise. Positions are 1-based, counting\n * only elements of that name, which is what XPath means by `position()` inside\n * a name test and is what every XML tool will agree with.\n */\n\n/** A location inside a part, or the part itself. */\nexport interface Location {\n /**\n * The part name, with its leading slash: `/ppt/slides/slide1.xml`.\n *\n * `/` means the finding is about the package rather than about any one part -\n * the archive shape, the content-type map, the relationship graph as a whole.\n */\n readonly part: string;\n /** The path to the element or attribute, or `null` for a whole-part finding. */\n readonly xpath: string | null;\n /** Byte offset of the node in the part's source, or `null`. For `cli bisect`. */\n readonly offset: number | null;\n}\n\n/** A location that names a part and nothing inside it. */\nexport function partLocation(part: string): Location {\n return { part, xpath: null, offset: null };\n}\n\n/** The location of the package itself: the archive, the content types, the graph. */\nexport const PACKAGE_LOCATION: Location = { part: '/', xpath: null, offset: null };\n\n/** 1-based position among same-named element siblings, or `null` if it is alone. */\nfunction positionAmongSiblings(element: XElement): number | null {\n const parent = element.parent;\n if (parent === undefined) return null;\n let position = 0;\n let seen = 0;\n for (const child of parent.children) {\n if (child.type !== 'element' || child.qname !== element.qname) continue;\n seen++;\n if (child === element) position = seen;\n }\n return seen > 1 ? position : null;\n}\n\n/**\n * The XPath of an element, from the document root.\n *\n * Never throws and never returns an empty string: a detached element - one\n * whose `parent` chain does not reach a root - still gets its own name, so a\n * finding built from a node the caller synthesised is degraded rather than\n * lost.\n */\nexport function xpathOf(element: XElement): string {\n const steps: string[] = [];\n for (let node: XElement | undefined = element; node !== undefined; node = node.parent) {\n const position = positionAmongSiblings(node);\n steps.push(position === null ? node.qname : node.qname + '[' + String(position) + ']');\n }\n steps.reverse();\n return '/' + steps.join('/');\n}\n\n/** The XPath of an attribute: its owner's path, then `/@qname`. */\nexport function xpathOfAttribute(owner: XElement, attr: XAttribute | string): string {\n const qname = typeof attr === 'string' ? attr : attr.qname;\n return xpathOf(owner) + '/@' + qname;\n}\n\n/** A location for an element inside a named part. */\nexport function elementLocation(part: string, element: XElement): Location {\n return { part, xpath: xpathOf(element), offset: element.start };\n}\n\n/**\n * A location for one attribute of an element.\n *\n * The offset is the attribute's own start when the element carries it, and the\n * element's start when it does not - which is the case that matters, because a\n * *missing* required attribute is a finding and it has to point somewhere.\n */\nexport function attributeLocation(part: string, element: XElement, qname: string): Location {\n const attr = attribute(element, qname);\n return {\n part,\n xpath: xpathOfAttribute(element, qname),\n offset: attr === undefined ? element.start : attr.start,\n };\n}\n\n/**\n * `line:column` for an offset, 1-based, or `null`.\n *\n * Not part of `Location`, because computing it means scanning the source from\n * the beginning and a report with three hundred findings would scan it three\n * hundred times. Callers that render a report for a human ask for it once, at\n * the point of rendering, for the findings they are about to show.\n */\nexport function lineColumn(source: string, offset: number): { line: number; column: number } {\n let line = 1;\n let lineStart = 0;\n const limit = Math.min(offset, source.length);\n for (let i = 0; i < limit; i++) {\n if (source.charCodeAt(i) === 0x0a) {\n line++;\n lineStart = i + 1;\n }\n }\n return { line, column: limit - lineStart + 1 };\n}\n\n/** Document order, for sorting findings within a part. */\nexport function inDocumentOrder(a: XNode, b: XNode): number {\n return a.start - b.start;\n}\n\n/** The root element's qname, for the handful of rules that dispatch on it. */\nexport function rootName(document: XDocument): string {\n return document.root.qname;\n}\n","import {\n CONTENT_TYPES_PART,\n isContentTypesStreamName,\n isRelationshipPartName,\n normalizePartName,\n type PartStore,\n type PartName,\n type ZipArchive,\n} from '@pptx-studio/opc';\nimport { parseXml, type XDocument } from '@pptx-studio/xml';\nimport type { Location } from './report/location.js';\nimport type { Finding, ReadProblem } from './report/report.js';\nimport { ruleById, type RuleId } from './rules/rules.js';\n\n/**\n * The state a rule reads, and the one method it writes.\n *\n * Every rule is `(ctx: Context) => void`. That is a deliberately small\n * interface, and it is the same shape `checkLayering({manifests, catalog})` and\n * `checkCorpus({manifests, files, ...})` already have in this repository, for\n * the same reason: a rule that takes a context and returns nothing is a rule\n * that can be run against a package assembled in a test, with no temporary\n * directory, no archive on disk and no other twenty-eight rules running beside\n * it obscuring which one fired.\n *\n * ## Everything is lazy, and everything is cached\n *\n * Twelve of the rules want the parsed tree of every XML part. Parsing each part\n * once per rule would be twelve passes over a deck that can be two hundred\n * megabytes. Parsing all of them up front would be one pass too many for the\n * package-level rules, which need no trees at all.\n *\n * So `document()` parses on first ask and remembers. A part that is not XML\n * returns `null` and is not asked again. A part that will not *parse* also\n * returns `null` - and records a `ReadProblem`, because a rule that silently\n * saw nothing is indistinguishable from a rule that found nothing, and those\n * are opposite answers.\n */\nexport interface Context {\n /** The package about to be handed over, or the one being inspected. */\n readonly store: PartStore;\n /** The archive bytes, when the caller had them. `null` when only a store was given. */\n readonly bytes: Uint8Array | null;\n /**\n * The archive those bytes describe, central directory only - nothing is\n * inflated to build it.\n *\n * `PartStore` deliberately does not expose this. It drops directory entries\n * on the way in, because a directory entry is not a part and carrying a thing\n * with no part name through the whole system would mean every consumer has to\n * remember it is there. That is right for the store and it leaves three rules\n * with nothing to look at: whether the archive has directory entries, whether\n * it carries a ZIP64 record, and what `[Content_Types].xml` actually *says* as\n * opposed to what parsing it produced.\n *\n * `null` when the caller passed a store and no bytes; the rules that need it\n * are then skipped with a reason rather than passing vacuously.\n */\n readonly archive: ZipArchive | null;\n /** The package as it was opened. `null` for an inspection with no history. */\n readonly baseline: PartStore | null;\n\n /** Part names in package order, `[Content_Types].xml` excluded - it is not a part. */\n parts(): readonly PartName[];\n /** A part's bytes, or `null` if it is not there. Never throws. */\n read(part: string): Uint8Array | null;\n /** Content type, or `undefined` when nothing in the map covers the part. */\n contentType(part: string): string | undefined;\n /** The parsed tree, cached. `null` for binary parts and for parts that will not parse. */\n document(part: string): XDocument | null;\n /**\n * `[Content_Types].xml` as the archive holds it, parsed.\n *\n * Not reachable through `parts()`: the content-type stream is not a part. It\n * has no content type of its own and nothing ever relates to it, which is why\n * `PartStore` keeps it outside the part map entirely.\n *\n * Read from the markup rather than from `store.contentTypes` for the reason\n * `rels.ts` gives at length: `ContentTypes.parse` collapses a duplicate\n * `Default` that agrees with itself and refuses one that does not, so a rule\n * that asks the parsed map whether there are duplicates is asking the one\n * object in the system that cannot answer.\n */\n contentTypesDocument(): XDocument | null;\n\n /** The same three, against the baseline. `null` throughout when there is none. */\n baselineRead(part: string): Uint8Array | null;\n baselineDocument(part: string): XDocument | null;\n\n /**\n * True when this session replaced or added the part.\n *\n * Derived from `PartInfo.fromArchive`, which is the store's own record of\n * whether a part's bytes still come from the archive it was opened from. It\n * is the only honest source for \"did we touch this\" - a byte comparison\n * cannot tell an edit that happened to produce identical bytes from no edit\n * at all, and the preservation rules care about the difference.\n */\n edited(part: string): boolean;\n\n add(rule: RuleId, where: Location, message: string): void;\n problem(part: string, message: string): void;\n}\n\nexport interface ContextInput {\n readonly store: PartStore;\n readonly bytes?: Uint8Array | null;\n readonly archive?: ZipArchive | null;\n readonly baseline?: PartStore | null;\n}\n\n/** Content types whose parts are XML, beyond everything ending in `+xml`. */\nconst XML_CONTENT_TYPES = new Set(['application/xml', 'text/xml']);\n\nfunction isXmlContentType(contentType: string | undefined): boolean {\n if (contentType === undefined) return false;\n const base = contentType.split(';')[0]!.trim().toLowerCase();\n return base.endsWith('+xml') || XML_CONTENT_TYPES.has(base);\n}\n\nclass RuntimeContext implements Context {\n readonly store: PartStore;\n readonly bytes: Uint8Array | null;\n readonly archive: ZipArchive | null;\n readonly baseline: PartStore | null;\n\n readonly findings: Finding[] = [];\n readonly problems: ReadProblem[] = [];\n\n #parts: PartName[] | null = null;\n readonly #documents = new Map<string, XDocument | null>();\n readonly #baselineDocuments = new Map<string, XDocument | null>();\n\n constructor(input: ContextInput) {\n this.store = input.store;\n this.bytes = input.bytes ?? null;\n this.archive = input.archive ?? null;\n this.baseline = input.baseline ?? null;\n }\n\n parts(): readonly PartName[] {\n this.#parts ??= this.store.partNames;\n return this.#parts;\n }\n\n read(part: string): Uint8Array | null {\n if (!this.store.has(part)) return null;\n try {\n return this.store.read(part);\n } catch (error) {\n this.problem(part, describe(error));\n return null;\n }\n }\n\n contentType(part: string): string | undefined {\n return this.store.contentTypeOf(part);\n }\n\n document(part: string): XDocument | null {\n const key = normalizePartName(part);\n const cached = this.#documents.get(key);\n if (cached !== undefined) return cached;\n const parsed = this.#parse(part, this.read(part));\n this.#documents.set(key, parsed);\n return parsed;\n }\n\n baselineDocument(part: string): XDocument | null {\n if (this.baseline === null) return null;\n const key = normalizePartName(part);\n const cached = this.#baselineDocuments.get(key);\n if (cached !== undefined) return cached;\n const parsed = this.#parse(part, this.baselineRead(part), true);\n this.#baselineDocuments.set(key, parsed);\n return parsed;\n }\n\n #parse(part: string, bytes: Uint8Array | null, quiet = false): XDocument | null {\n if (bytes === null) return null;\n // The content type decides, not the extension. A `.bin` OLE object and a\n // `.png` are both binary and neither would tokenize; more to the point, an\n // `.xml` extension covers a `Default` that some producer typed\n // `application/octet-stream`, and parsing that would be us disagreeing with\n // the package about what it holds.\n if (!isRelationshipPartName(part) && !isXmlContentType(this.contentType(part))) return null;\n try {\n return parseXml(bytes);\n } catch (error) {\n // Not a rule violation. `@pptx-studio/xml` refuses a DOCTYPE, a bad\n // encoding and markup that is not well formed, and each of those is a\n // fact about the file rather than about one of the twenty-nine rules.\n // Recording it as a problem keeps the report honest: the rules that\n // wanted this part did not run on it.\n if (!quiet) this.problem(part, describe(error));\n return null;\n }\n }\n\n #contentTypesDocument: XDocument | null | undefined;\n\n contentTypesDocument(): XDocument | null {\n if (this.#contentTypesDocument !== undefined) return this.#contentTypesDocument;\n this.#contentTypesDocument = null;\n const archive = this.archive;\n if (archive !== null) {\n const entry = archive.entries.find((e) => isContentTypesStreamName(e.name));\n if (entry !== undefined) {\n try {\n this.#contentTypesDocument = parseXml(archive.read(entry));\n } catch (error) {\n this.problem(CONTENT_TYPES_PART, describe(error));\n }\n }\n }\n return this.#contentTypesDocument;\n }\n\n baselineRead(part: string): Uint8Array | null {\n if (this.baseline === null || !this.baseline.has(part)) return null;\n try {\n return this.baseline.read(part);\n } catch {\n return null;\n }\n }\n\n edited(part: string): boolean {\n return this.store.info(part)?.fromArchive === false;\n }\n\n add(rule: RuleId, where: Location, message: string): void {\n const definition = ruleById(rule);\n if (definition === undefined) return;\n this.findings.push({\n rule,\n severity: definition.severity,\n category: definition.category,\n where,\n message,\n // Filled in by the driver, which is the only thing that knows whether a\n // baseline pass ran. A rule never decides its own finding's history.\n origin: 'unknown',\n });\n }\n\n problem(part: string, message: string): void {\n const already = this.problems.some((p) => p.part === part && p.message === message);\n if (!already) this.problems.push({ part, message });\n }\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n const code = (error as { code?: unknown }).code;\n return typeof code === 'string' ? code + ': ' + error.message : error.message;\n }\n return String(error);\n}\n\nexport function createContext(input: ContextInput): RuntimeContext {\n return new RuntimeContext(input);\n}\n\nexport type { RuntimeContext };\n","import {\n isRelationshipPartName,\n normalizePartName,\n resolveRelativeTarget,\n sourcePartNameForRels,\n} from '@pptx-studio/opc';\nimport { attributeValue, childElements, type XElement } from '@pptx-studio/xml';\nimport type { Context } from './context.js';\n\n/**\n * Relationship parts, read as XML rather than through `Relationships`.\n *\n * This is not duplication for its own sake, and the reason is worth stating\n * because the obvious code - call `store.relationships(part)` - is wrong here in\n * a way that is invisible until a rule fails to fire.\n *\n * `Relationships.parse` **refuses** a duplicate `Id`, an `Id` that is not an\n * `xsd:ID`, and an empty `Target`. It has to: it is the type the rest of the\n * codebase uses to look relationships up, and a collection with two `rId3`s\n * cannot answer the only question anyone asks it. But three of the twenty-nine\n * rules are *about* exactly those defects, and a rule that can only see files\n * its own parser already accepted can never report them. Going through that\n * parser would turn every one of those findings into \"this part could not be\n * read\", which is true and useless.\n *\n * So the rules read the markup. That also buys the thing the plan asks for: a\n * finding gets an XPath into the `.rels` part - `/Relationships/Relationship[4]`\n * - instead of a part name and an apology.\n */\n\nconst REL_NS = 'http://schemas.openxmlformats.org/package/2006/relationships';\n\nexport interface RawRelationship {\n readonly id: string;\n readonly type: string;\n readonly target: string;\n /** `Internal` unless the attribute says otherwise; the attribute is optional. */\n readonly targetMode: string;\n /** The `<Relationship>` element, for the finding's location. */\n readonly element: XElement;\n}\n\nexport interface RelsPart {\n /** The `.rels` part's own name, e.g. `/ppt/slides/_rels/slide1.xml.rels`. */\n readonly partName: string;\n /** The part it describes, e.g. `/ppt/slides/slide1.xml`. `/` for the root rels. */\n readonly source: string;\n readonly relationships: readonly RawRelationship[];\n readonly root: XElement;\n}\n\n/**\n * Every relationship part in the package, parsed.\n *\n * A `.rels` whose root is not `Relationships` in the OPC namespace is skipped\n * and recorded as a problem, because there is nothing sensible to say about it\n * rule by rule and saying it once is better than saying it four times.\n */\nconst CACHE = new WeakMap<Context, readonly RelsPart[]>();\n\nexport function readRelsParts(ctx: Context): readonly RelsPart[] {\n const cached = CACHE.get(ctx);\n if (cached !== undefined) return cached;\n const parts = scanRelsParts(ctx);\n CACHE.set(ctx, parts);\n return parts;\n}\n\n/**\n * Memoised above, because five of the twenty-nine rules want this list and each\n * would otherwise re-walk every `.rels` part in the package. The parsed trees\n * are already cached on the context; what is saved here is the element scan and\n * the allocation, which on a three-hundred-slide deck is five passes over a\n * thousand relationship parts for one answer that cannot have changed.\n *\n * Keyed by context rather than by store, so nothing survives one validation run\n * into the next.\n */\nfunction scanRelsParts(ctx: Context): readonly RelsPart[] {\n const out: RelsPart[] = [];\n for (const partName of ctx.parts()) {\n if (!isRelationshipPartName(partName)) continue;\n const document = ctx.document(partName);\n if (document === null) continue;\n\n const root = document.root;\n if (root.local !== 'Relationships') {\n ctx.problem(partName, 'root element is <' + root.qname + '>, not <Relationships>');\n continue;\n }\n\n let source: string;\n try {\n source = partName === '/_rels/.rels' ? '/' : sourcePartNameForRels(partName);\n } catch {\n ctx.problem(partName, 'is not a well-formed relationship part name');\n continue;\n }\n\n const relationships: RawRelationship[] = [];\n for (const child of childElements(root)) {\n if (child.local !== 'Relationship') continue;\n relationships.push({\n id: attributeValue(child, 'Id') ?? '',\n type: attributeValue(child, 'Type') ?? '',\n target: attributeValue(child, 'Target') ?? '',\n targetMode: attributeValue(child, 'TargetMode') ?? 'Internal',\n element: child,\n });\n }\n out.push({ partName, source, relationships, root });\n }\n return out;\n}\n\n/** The OPC relationships namespace, for the rules that check the root element. */\nexport { REL_NS };\n\nexport interface ResolvedTarget {\n /** The absolute part name the target names, or `null` when it will not resolve. */\n readonly part: string | null;\n /** Why it would not resolve. `null` when it did. */\n readonly failure: string | null;\n}\n\n/**\n * Resolve an internal target against the folder of the part that owns the\n * `.rels` - never against the package root, and never against the `.rels`\n * part's own folder.\n *\n * The distinction is the whole of rule `V008`. `_rels/` is a directory in the\n * archive but not in the resolution model: a `Target=\"../media/image1.png\"` in\n * `/ppt/slides/_rels/slide1.xml.rels` resolves against `/ppt/slides/`, giving\n * `/ppt/media/image1.png`. Resolving it against `/ppt/slides/_rels/` instead\n * yields `/ppt/slides/media/image1.png`, which is one directory too deep and is\n * why a rebuilt deck loses every image at once rather than one of them.\n */\nexport function resolveTarget(source: string, target: string): ResolvedTarget {\n try {\n return { part: resolveRelativeTarget(source, target), failure: null };\n } catch (error) {\n return { part: null, failure: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/** Relationship ids declared in a part's `.rels`, for reference checking. */\nexport function idsOf(rels: RelsPart | undefined): ReadonlySet<string> {\n const ids = new Set<string>();\n for (const rel of rels?.relationships ?? []) ids.add(rel.id);\n return ids;\n}\n\n/** `.rels` parts keyed by the **source** part they describe, normalised. */\nexport function bySource(parts: readonly RelsPart[]): ReadonlyMap<string, RelsPart> {\n const map = new Map<string, RelsPart>();\n for (const part of parts) {\n map.set(part.source === '/' ? '/' : normalizePartName(part.source), part);\n }\n return map;\n}\n","import {\n checkPartNameCollisions,\n CONTENT_TYPES_PART,\n CONTENT_TYPE,\n FONT_DATA_CONTENT_TYPE,\n FONT_DATA_EXTENSION,\n partExtension,\n REL_TYPE,\n validatePartName,\n} from '@pptx-studio/opc';\nimport { attributeValue, childElements } from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation, PACKAGE_LOCATION, partLocation } from '../report/location.js';\nimport { readRelsParts, resolveTarget } from '../rels.js';\n\n/**\n * `V001` … `V005`: the container.\n *\n * These five run before any markup is looked at, and they are the ones whose\n * failure mode is \"PowerPoint declines to open the file at all\" rather than\n * \"the slide renders wrong\". The package layer has no partial credit: a part\n * with no content type is not a part with an unknown type, it is a stream\n * nothing is allowed to interpret.\n */\n\n/** Every part resolves to a content type. */\nexport function v001ContentTypeCoverage(ctx: Context): void {\n for (const part of ctx.parts()) {\n if (ctx.contentType(part) !== undefined) continue;\n const extension = partExtension(part);\n ctx.add(\n 'V001',\n partLocation(part),\n 'no content type: nothing in [Content_Types].xml covers it. Add an Override for the part, ' +\n (extension === ''\n ? 'or give it an extension a Default covers.'\n : 'or a Default for the \"' + extension + '\" extension.'),\n );\n }\n}\n\n/**\n * The content-type map holds together.\n *\n * Four separate things, one rule, because they are one question - \"does this\n * map say exactly one thing about every part\" - and a caller who has to\n * remember four rule ids to know whether their content types are sound is a\n * caller who will remember three.\n */\nexport function v002ContentTypeMap(ctx: Context): void {\n const document = ctx.contentTypesDocument();\n\n // Duplicates are only visible in the markup. See `Context.contentTypesDocument`.\n if (document === null) {\n if (ctx.archive === null) {\n // Said out loud rather than quietly skipped. The rest of this rule still\n // runs, so it is a narrower check than it looks like, and a report that\n // does not say so is a report that overstates itself.\n ctx.problem(\n CONTENT_TYPES_PART,\n 'not available: only a PartStore was supplied, so V002 checked the parsed map and not ' +\n 'the markup. A duplicate <Default> or <Override> is visible only in the markup.',\n );\n } else {\n ctx.add(\n 'V002',\n partLocation(CONTENT_TYPES_PART),\n 'the content-type stream is missing or would not parse.',\n );\n }\n } else {\n const seenDefault = new Map<string, number>();\n const seenOverride = new Map<string, number>();\n for (const child of childElements(document.root)) {\n if (child.local === 'Default') {\n const extension = (attributeValue(child, 'Extension') ?? '').toLowerCase();\n const count = (seenDefault.get(extension) ?? 0) + 1;\n seenDefault.set(extension, count);\n if (count === 2) {\n // M2.5 is unconditional and PowerPoint enforces it literally: two\n // `<Default>`s for one extension are refused with `0x80CB8000` even\n // when the two elements are byte-identical.\n ctx.add(\n 'V002',\n elementLocation(CONTENT_TYPES_PART, child),\n 'the \"' +\n extension +\n '\" extension has two <Default> entries. PowerPoint refuses a duplicate even when ' +\n 'the two agree.',\n );\n }\n } else if (child.local === 'Override') {\n const partName = attributeValue(child, 'PartName') ?? '';\n const key = partName.toLowerCase();\n const count = (seenOverride.get(key) ?? 0) + 1;\n seenOverride.set(key, count);\n if (count === 2) {\n ctx.add(\n 'V002',\n elementLocation(CONTENT_TYPES_PART, child),\n partName + ' has two <Override> entries.',\n );\n }\n if (partName !== '' && !ctx.store.has(partName)) {\n ctx.add(\n 'V002',\n elementLocation(CONTENT_TYPES_PART, child),\n 'an <Override> names ' + partName + ', which is not in the package.',\n );\n }\n }\n }\n }\n\n // The `fntdata` Default. Omitting it is the canonical \"PowerPoint found a\n // problem with content\" bug, and it is invisible until a user without the\n // font opens the file - the deck is otherwise complete and the relationship,\n // the `p:embeddedFont` entry and the part itself are all correct.\n const fontParts = ctx\n .parts()\n .filter((part) => partExtension(part).toLowerCase() === FONT_DATA_EXTENSION);\n if (fontParts.length > 0) {\n const declared = ctx.store.contentTypes.defaults.find(\n (entry) => entry.extension.toLowerCase() === FONT_DATA_EXTENSION,\n );\n if (declared === undefined) {\n ctx.add(\n 'V002',\n partLocation(CONTENT_TYPES_PART),\n 'the package has ' +\n String(fontParts.length) +\n ' .fntdata part(s) and no <Default Extension=\"fntdata\" ContentType=\"' +\n FONT_DATA_CONTENT_TYPE +\n '\"/>. PowerPoint reports the file as having a problem with its content.',\n );\n } else if (declared.contentType.toLowerCase() !== FONT_DATA_CONTENT_TYPE.toLowerCase()) {\n ctx.add(\n 'V002',\n partLocation(CONTENT_TYPES_PART),\n 'the fntdata Default is typed \"' +\n declared.contentType +\n '\"; embedded fonts are \"' +\n FONT_DATA_CONTENT_TYPE +\n '\".',\n );\n }\n }\n}\n\n/** No directory entries, no ZIP64 record. */\nexport function v003ArchiveShape(ctx: Context): void {\n const archive = ctx.archive;\n if (archive === null) return;\n\n for (const entry of archive.entries) {\n if (!entry.isDirectory) continue;\n ctx.add(\n 'V003',\n PACKAGE_LOCATION,\n 'the archive carries a directory entry, \"' +\n entry.name +\n '\". No OPC part name may end in a slash, so nothing in the package can name it.',\n );\n }\n\n if (ctx.bytes !== null && hasZip64Locator(ctx.bytes)) {\n ctx.add(\n 'V003',\n PACKAGE_LOCATION,\n 'the archive carries a ZIP64 end-of-central-directory locator. Our writer emits ZIP32 ' +\n 'only, so one in a package we produced means a size or offset field overflowed.',\n );\n }\n}\n\n/**\n * The ZIP64 locator signature, searched backwards from the end.\n *\n * The locator sits immediately before the end-of-central-directory record,\n * which is within 64 KB + 22 bytes of the end once a comment is allowed for.\n * Same computation `@pptx-studio/census` makes; duplicated rather than shared\n * because `census` is a sibling at layer 1 and depending on it to answer one\n * boolean would put a whole feature scanner in the export path.\n */\nfunction hasZip64Locator(bytes: Uint8Array): boolean {\n if (bytes.byteLength < 20) return false;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const from = Math.max(0, bytes.byteLength - 0x10000 - 40);\n for (let at = bytes.byteLength - 20; at >= from; at--) {\n if (view.getUint32(at, true) === 0x07064b50) return true;\n }\n return false;\n}\n\n/**\n * Part names, with `M1.8` raised from warning to fatal.\n *\n * `@pptx-studio/opc` rates a percent-escape of an unreserved character a\n * warning, and that is right *there*: the package layer has to open what it is\n * given, and a file that arrives with `%5F` in a part name is a file the user\n * still wants to see. Here we are about to write one, and PowerPoint refuses\n * it with `0x808D1005` - measured nine for nine on one-name packages. Raising\n * the severity at the point of writing rather than at the point of reading is\n * the whole shape of the read-leniently/write-strictly split this project uses\n * everywhere.\n */\nexport function v004PartNames(ctx: Context): void {\n for (const part of ctx.parts()) {\n for (const violation of validatePartName(part)) {\n // Every violation, warning or not. `validatePartName` grades severity for\n // a *reader*, which has to open what it is given; here we are about to\n // write one, and a part name that is merely non-conformant is a part name\n // we should not be emitting. An odd name a deck arrived with is not\n // trapped by this - it comes back `inherited` and does not block the\n // export. See `report.ts`.\n ctx.add('V004', partLocation(part), violation.rule + ': ' + violation.message);\n }\n }\n\n for (const collision of checkPartNameCollisions([...ctx.parts()])) {\n ctx.add('V004', partLocation(collision.names[0]), collision.rule + ': ' + collision.message);\n }\n}\n\n/** The main presentation part: exactly one, of a type that matches the file. */\nconst MAIN_PART_TYPES = new Set<string>([\n CONTENT_TYPE.presentation,\n CONTENT_TYPE.template,\n CONTENT_TYPE.slideshow,\n 'application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml',\n 'application/vnd.ms-powerpoint.template.macroEnabled.main+xml',\n 'application/vnd.ms-powerpoint.slideshow.macroEnabled.main+xml',\n]);\n\nexport function v005MainPart(ctx: Context): void {\n const rootRels = readRelsParts(ctx).find((rels) => rels.source === '/');\n if (rootRels === undefined) {\n ctx.add(\n 'V005',\n partLocation('/_rels/.rels'),\n 'the package has no root relationship part. It is the only way in to a .pptx; without it ' +\n 'nothing can be reached and PowerPoint reports the file as corrupted and unreadable.',\n );\n return;\n }\n\n const officeDocuments = rootRels.relationships.filter(\n (rel) => rel.type === REL_TYPE.officeDocument,\n );\n if (officeDocuments.length === 0) {\n ctx.add(\n 'V005',\n partLocation(rootRels.partName),\n 'no officeDocument relationship. Nothing names the main presentation part.',\n );\n return;\n }\n if (officeDocuments.length > 1) {\n for (const rel of officeDocuments.slice(1)) {\n ctx.add(\n 'V005',\n elementLocation(rootRels.partName, rel.element),\n 'a second officeDocument relationship (' +\n rel.id +\n ' -> ' +\n rel.target +\n '). Exactly one part is the main part.',\n );\n }\n }\n\n const main = officeDocuments[0]!;\n const resolved = resolveTarget(rootRels.source, main.target);\n if (resolved.part === null) {\n ctx.add(\n 'V005',\n elementLocation(rootRels.partName, main.element),\n 'the officeDocument target does not resolve: ' + (resolved.failure ?? 'unknown reason'),\n );\n return;\n }\n if (!ctx.store.has(resolved.part)) {\n ctx.add(\n 'V005',\n elementLocation(rootRels.partName, main.element),\n 'the officeDocument target ' + resolved.part + ' is not in the package.',\n );\n return;\n }\n\n const contentType = ctx.contentType(resolved.part);\n if (contentType === undefined || !MAIN_PART_TYPES.has(contentType)) {\n ctx.add(\n 'V005',\n partLocation(resolved.part),\n 'the main part is typed ' +\n (contentType === undefined ? '(nothing)' : '\"' + contentType + '\"') +\n ', which is not a PresentationML main-part type. PowerPoint also checks this against ' +\n 'the file extension and refuses the pair when they disagree, which is why a ' +\n 'macro-enabled deck has to be written .pptm.',\n );\n }\n}\n","import {\n CONTENT_TYPE,\n isRelationshipPartName,\n isValidRelationshipId,\n normalizePartName,\n REL_TYPE,\n} from '@pptx-studio/opc';\nimport {\n attributeNamespaceOf,\n descendantElements,\n NS,\n type XAttribute,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { attributeLocation, elementLocation, partLocation } from '../report/location.js';\nimport { bySource, readRelsParts, resolveTarget, type RelsPart } from '../rels.js';\n\n/**\n * `V006` … `V009`: the relationship graph.\n *\n * The graph is where a `.pptx` keeps almost everything that is not text. A\n * slide does not name its layout, a picture does not name its image, and a\n * chart does not name its workbook: each of them names an `rId`, and the `rId`\n * means something only inside one `.rels` part. Three consequences run through\n * all four rules below.\n *\n * **Ids are scoped, not global.** `rId3` in `slide1.xml.rels` and `rId3` in\n * `slide2.xml.rels` are unrelated. A global id registry is not an optimisation,\n * it is a bug, and it is a bug that works fine on every one-slide test deck.\n *\n * **Dangling is fatal; orphaned is harmless.** A reference to a relationship\n * that is not there, or a relationship to a part that is not there, breaks the\n * file. A relationship nothing references does not. That asymmetry is what\n * decides the direction media garbage collection is allowed to be aggressive\n * in, and getting it backwards is how a \"clean-up\" pass deletes the layouts a\n * user was about to switch to.\n *\n * **Targets resolve against the source part's folder.** Not the package root,\n * and not the `.rels` file's own folder.\n */\n\n/**\n * Attributes in the relationship namespace that name a relationship id.\n *\n * All of them do, in practice - `r:id`, `r:embed`, `r:link`, `r:pict`,\n * `r:dm`, `r:lo`, `r:qs`, `r:cs`, `r:href` and the rest. Rather than list the\n * ones we know, this rule matches on the *namespace*, so an attribute from a\n * schema we have not read yet is checked rather than skipped. The two things\n * that must not be treated as ids are handled explicitly below.\n */\nfunction isRelationshipReference(owner: XElement, attr: XAttribute): boolean {\n if (attr.prefix === '' || attr.prefix === 'xmlns') return false;\n // `r:` is conventional and not guaranteed, so the prefix is resolved rather\n // than compared. A part is free to bind the relationship namespace to any\n // prefix, and matching on the string `r` would silently stop checking one\n // that did.\n return attributeNamespaceOf(owner, attr) === NS.r;\n}\n\n/** Every `r:*` reference resolves in its own part's `.rels`. */\nexport function v006ReferencesResolve(ctx: Context): void {\n const relsBySource = bySource(readRelsParts(ctx));\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n\n const rels = relsBySource.get(normalizePartName(part));\n const known = new Set((rels?.relationships ?? []).map((rel) => rel.id));\n\n for (const element of descendantElements(document.root)) {\n for (const attr of element.attributes) {\n if (!isRelationshipReference(element, attr)) continue;\n // An empty value is not a dangling reference, it is the absence of one.\n // `<a:hlinkClick r:id=\"\" action=\"ppaction://noaction\"/>` is what\n // PowerPoint writes for an action with no target, and it is common.\n if (attr.value === '') continue;\n if (known.has(attr.value)) continue;\n ctx.add(\n 'V006',\n attributeLocation(part, element, attr.qname),\n rels === undefined\n ? '<' +\n element.qname +\n ' ' +\n attr.qname +\n '=\"' +\n attr.value +\n '\"> refers to a relationship, but this part has no .rels at all.'\n : '<' +\n element.qname +\n ' ' +\n attr.qname +\n '=\"' +\n attr.value +\n '\"> names a relationship that ' +\n rels.partName +\n ' does not declare. Ids are scoped to one .rels part; this one has ' +\n (known.size === 0 ? 'none' : [...known].sort().join(', ')) +\n '.',\n );\n }\n }\n }\n}\n\n/** Relationship ids are unique within a `.rels` and are `xsd:ID`s. */\nexport function v007RelationshipIds(ctx: Context): void {\n for (const rels of readRelsParts(ctx)) {\n const seen = new Map<string, number>();\n for (const rel of rels.relationships) {\n if (rel.id === '') {\n ctx.add('V007', elementLocation(rels.partName, rel.element), 'a <Relationship> has no Id.');\n continue;\n }\n if (!isValidRelationshipId(rel.id)) {\n ctx.add(\n 'V007',\n elementLocation(rels.partName, rel.element),\n 'Id=\"' +\n rel.id +\n '\" is not an xsd:ID. An xsd:ID is an XML NCName: it cannot begin with a digit and ' +\n 'cannot contain a space or a colon.',\n );\n }\n const count = (seen.get(rel.id) ?? 0) + 1;\n seen.set(rel.id, count);\n if (count === 2) {\n ctx.add(\n 'V007',\n elementLocation(rels.partName, rel.element),\n 'Id=\"' +\n rel.id +\n '\" appears twice. Which target a reference to it means would be undecidable.',\n );\n }\n }\n }\n}\n\n/** Internal targets resolve, stay inside the package, and name a part that exists. */\nexport function v008TargetsResolve(ctx: Context): void {\n for (const rels of readRelsParts(ctx)) {\n for (const rel of rels.relationships) {\n if (rel.targetMode === 'External') continue;\n if (rel.targetMode !== 'Internal') {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n 'TargetMode=\"' + rel.targetMode + '\" is neither Internal nor External.',\n );\n continue;\n }\n if (rel.target === '') {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n rel.id + ' has an empty Target.',\n );\n continue;\n }\n const resolved = resolveTarget(rels.source, rel.target);\n if (resolved.part === null) {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n rel.id +\n ' -> \"' +\n rel.target +\n '\" does not resolve against ' +\n rels.source +\n ': ' +\n (resolved.failure ?? 'unknown reason'),\n );\n continue;\n }\n if (!ctx.store.has(resolved.part)) {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n rel.id +\n ' -> ' +\n resolved.part +\n ' names a part that is not in the package. A dangling relationship is fatal where an ' +\n 'orphaned one is harmless, which is why garbage collection may only ever be ' +\n 'aggressive in the other direction.',\n );\n }\n }\n }\n}\n\n/** The chartex content type. Not in `CONTENT_TYPE`: it is Microsoft's, not ECMA's. */\nconst CHART_EX_CONTENT_TYPE = 'application/vnd.ms-office.chartex+xml';\n\n/**\n * The ECMA `customXml` relationship type.\n *\n * A `p:contentPart` reached by *this* type is a whole-package refusal, while\n * the Microsoft 2010 type of the same name opens - and so do two relationship\n * types that make no sense at all. PowerPoint validates that one type rather\n * than types in general, which is a strange enough finding that it is worth\n * writing the constant down beside the rule that uses it.\n */\nconst REL_CUSTOM_XML_ECMA =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml';\n\n/** Elements whose `r:` attribute means \"this is a media object's target\". */\nconst MEDIA_REFERENCE_ELEMENTS = new Set(['audioFile', 'videoFile', 'media']);\n\n/**\n * The edges a part must have, and the ones it must not.\n *\n * Four findings, none of them in any schema. See the rule's `why` in\n * `rules.ts` for the bisections; the code below is deliberately a table read\n * against the package rather than four separate walks.\n */\nexport function v009RequiredEdges(ctx: Context): void {\n const relsParts = readRelsParts(ctx);\n const relsBySource = bySource(relsParts);\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const contentType = ctx.contentType(part);\n const rels = relsBySource.get(normalizePartName(part));\n\n if (contentType === CONTENT_TYPE.slide) {\n requireExactlyOne(ctx, part, rels, REL_TYPE.slideLayout, CONTENT_TYPE.slideLayout, 'layout');\n } else if (contentType === CONTENT_TYPE.slideLayout) {\n requireExactlyOne(ctx, part, rels, REL_TYPE.slideMaster, CONTENT_TYPE.slideMaster, 'master');\n } else if (contentType === CHART_EX_CONTENT_TYPE) {\n // A `cx:chartSpace` with no `.rels` of its own is a whole-package\n // refusal, including one PowerPoint wrote itself. The classic\n // `c:chartSpace` needs neither of these.\n for (const [type, label] of [\n ['http://schemas.microsoft.com/office/2011/relationships/chartStyle', 'chartStyle'],\n [\n 'http://schemas.microsoft.com/office/2011/relationships/chartColorStyle',\n 'chartColorStyle',\n ],\n ] as const) {\n if ((rels?.relationships ?? []).some((rel) => rel.type === type)) continue;\n ctx.add(\n 'V009',\n partLocation(part),\n 'a chartex part with no ' +\n label +\n ' relationship. Unlike a classic c:chartSpace, which needs neither, a cx:chartSpace ' +\n 'without both is a whole-package refusal.',\n );\n }\n }\n }\n\n // `p:contentPart` reached by the ECMA customXml type.\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n const rels = relsBySource.get(normalizePartName(part));\n if (rels === undefined) continue;\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'contentPart') continue;\n for (const attr of element.attributes) {\n if (attr.local !== 'id' || attr.prefix === '') continue;\n const relationship = rels.relationships.find((rel) => rel.id === attr.value);\n if (relationship?.type !== REL_CUSTOM_XML_ECMA) continue;\n ctx.add(\n 'V009',\n attributeLocation(part, element, attr.qname),\n 'a <' +\n element.qname +\n '> reached by the ECMA customXml relationship type is a whole-package refusal. The ' +\n 'Microsoft 2010 type of the same name opens; PowerPoint validates this one type ' +\n 'rather than types in general.',\n );\n }\n }\n }\n\n checkSharedMedia(ctx, relsBySource);\n}\n\nfunction requireExactlyOne(\n ctx: Context,\n part: string,\n rels: RelsPart | undefined,\n type: string,\n targetContentType: string,\n label: string,\n): void {\n const matching = (rels?.relationships ?? []).filter((rel) => rel.type === type);\n if (matching.length !== 1) {\n ctx.add(\n 'V009',\n partLocation(part),\n 'has ' +\n String(matching.length) +\n ' ' +\n label +\n ' relationship(s); it needs exactly one. The binding lives only in the .rels part - ' +\n 'nothing in the part itself names its ' +\n label +\n ' - so zero and two are both whole-package refusals.',\n );\n return;\n }\n const rel = matching[0]!;\n const resolved = resolveTarget(rels!.source, rel.target);\n if (resolved.part === null || !ctx.store.has(resolved.part)) {\n // Reported by `V008` as a dangling target; the extra thing this rule knows\n // is that it is *this* edge, which is the one that cannot be missing.\n ctx.add(\n 'V009',\n elementLocation(rels!.partName, rel.element),\n 'the ' + label + ' relationship points at a part that is not in the package.',\n );\n return;\n }\n const actual = ctx.contentType(resolved.part);\n if (actual !== targetContentType) {\n ctx.add(\n 'V009',\n elementLocation(rels!.partName, rel.element),\n 'the ' +\n label +\n ' relationship resolves to ' +\n resolved.part +\n ', which is typed ' +\n (actual === undefined ? '(nothing)' : '\"' + actual + '\"') +\n ' rather than \"' +\n targetContentType +\n '\". One pointing at a master instead was built as a single change and refused.',\n );\n }\n}\n\n/**\n * A media part that is both a transition sound and a media object's target.\n *\n * The only refusal we have measured whose message is \"PowerPoint could not open\n * the file\" rather than \"the file or directory is corrupted and unreadable\" -\n * which is worth recording, because the message is the only signal there is.\n * Two copies of the same bytes open; one shared copy does not.\n */\nfunction checkSharedMedia(ctx: Context, relsBySource: ReadonlyMap<string, RelsPart>): void {\n const asTransitionSound = new Map<string, string>();\n const asMediaObject = new Map<string, string>();\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n const rels = relsBySource.get(normalizePartName(part));\n if (rels === undefined) continue;\n\n for (const element of descendantElements(document.root)) {\n const isSound = element.local === 'snd';\n const isMedia = MEDIA_REFERENCE_ELEMENTS.has(element.local);\n if (!isSound && !isMedia) continue;\n for (const attr of element.attributes) {\n if (attr.prefix === '' || attr.value === '') continue;\n if (attr.local !== 'embed' && attr.local !== 'link') continue;\n const rel = rels.relationships.find((r) => r.id === attr.value);\n if (rel === undefined || rel.targetMode === 'External') continue;\n const target = resolveTarget(rels.source, rel.target).part;\n if (target === null) continue;\n (isSound ? asTransitionSound : asMediaObject).set(normalizePartName(target), part);\n }\n }\n }\n\n for (const [target, soundOwner] of asTransitionSound) {\n const mediaOwner = asMediaObject.get(target);\n if (mediaOwner === undefined) continue;\n ctx.add(\n 'V009',\n partLocation(target),\n 'is both a transition sound (from ' +\n soundOwner +\n ') and a media object target (from ' +\n mediaOwner +\n '). Two copies of the same bytes open; one shared copy is a refusal.',\n );\n }\n}\n","import { isRelationshipPartName } from '@pptx-studio/opc';\nimport {\n attributeValue,\n childElements,\n childRanks,\n descendantElements,\n elementKey,\n isSchemaNamespace,\n namespaceOf,\n outOfOrderChildren,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation, xpathOf } from '../report/location.js';\n\n/**\n * `V010` … `V012`: where children are allowed to be.\n *\n * OOXML complex types are `xsd:sequence` almost everywhere, and this is the\n * category with the best-attested consequence in the whole appendix: Microsoft's\n * own Open XML SDK shipped a regression that swapped two elements in\n * `slideMaster1.xml`, changed nothing else, and PowerPoint refused the file.\n *\n * The ranks come from `@pptx-studio/xml`'s generated table, which is built from\n * the ECMA-376 Transitional schemas and checked against 194 148 elements\n * PowerPoint wrote. That second number is what makes the rule safe to make\n * fatal: a table generated from a standard and never compared with reality\n * would be a very confident way to reject files that work.\n *\n * The three rules divide the question by what the table can and cannot see:\n *\n * - `V010` - the child is in the model but in the wrong place.\n * - `V011` - `extLst` last, which has to hold in the places the table cannot\n * rank at all.\n * - `V012` - the child is not in the model.\n *\n * `V010` skips anything it cannot rank, which is correct for ordering and is\n * exactly the blind spot `V012` exists to cover.\n */\n\n/** Children in schema-sequence order. */\nexport function v010SchemaOrder(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n for (const problem of outOfOrderChildren(element)) {\n ctx.add(\n 'V010',\n { part, xpath: xpathOf(element), offset: problem.at },\n problem.detail +\n '. OOXML complex types are xsd:sequence and PowerPoint enforces the order literally.',\n );\n }\n });\n}\n\n/**\n * `extLst` is last, and every `a:ext` names its extension.\n *\n * There is exactly one type in the whole generated table where `extLst` is not\n * last: `p:control`, whose model is `extLst` then `pic`. That is not an\n * exception worth handling gracefully - `V025` refuses `p:control` outright,\n * because PowerPoint refuses it in all eight forms we tried - but it is skipped\n * here rather than reported twice.\n */\nexport function v011ExtLstLast(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'extLst') return;\n const parent = element.parent;\n if (parent === undefined || parent.local === 'control') return;\n\n const siblings = childElements(parent);\n const last = siblings[siblings.length - 1];\n if (last !== element) {\n ctx.add(\n 'V011',\n elementLocation(part, element),\n '<' +\n element.qname +\n '> is followed by <' +\n (last?.qname ?? '?') +\n '> inside <' +\n parent.qname +\n '>. An extension list is last in every type that has one.',\n );\n }\n\n for (const ext of childElements(element)) {\n if (ext.local !== 'ext') continue;\n const uri = attributeValue(ext, 'uri');\n if (uri !== undefined && uri !== '') continue;\n ctx.add(\n 'V011',\n elementLocation(part, ext),\n '<' +\n ext.qname +\n '> has no @uri. The uri is the only identity an extension has, and the contract for ' +\n 'extension markup is that it is carried through untouched *keyed by that uri* - so one ' +\n 'without it cannot be preserved, only guessed at.',\n );\n }\n });\n}\n\n/**\n * No child in a parent whose content model has no place for it.\n *\n * Deliberately conservative in four ways, because a false positive here refuses\n * a file somebody wanted:\n *\n * - only parents the generated table knows are checked, and `childRanks`\n * returns `undefined` for every open (`xsd:any`) type, so `a:ext`,\n * `p:ext` and `a:graphicData` - the three places the plan forbids us to\n * rebuild - are never looked at;\n * - **only children in the four namespaces the table was generated from.**\n * This is the one the corpus taught us. `childRanks` collapses \"the schema\n * forbids this here\" and \"we have never read this schema\" into the same\n * `undefined`, which is right for a caller trying to insert a child and\n * catastrophic for one trying to judge an existing one: without the\n * namespace test, the rule fired on forty `mc:AlternateContent` elements,\n * on `a14:m`, on `p14:honeycomb` and on `a37-mce`'s deliberate `zz:` markup -\n * which is `mc:Ignorable` extension markup doing exactly what it exists for;\n * - `mc:Choice` and `mc:Fallback` are unrankable parents, so their contents\n * fall out for free.\n */\nexport function v012UnexpectedChild(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n const ranks = childRanks(element);\n if (ranks === undefined) return;\n for (const child of childElements(element)) {\n if (!isSchemaNamespace(namespaceOf(child))) continue;\n const key = elementKey(child);\n if (key === undefined || ranks.has(key)) continue;\n ctx.add(\n 'V012',\n elementLocation(part, child),\n '<' +\n child.qname +\n '> is not a child <' +\n element.qname +\n '> admits. `a:ahXY` or `a:cxn` placed directly under `a:custGeom`, without its ' +\n '`a:ahLst`/`a:cxnLst` wrapper, is the case that made this a rule: a whole-package ' +\n 'refusal that the ordering rule cannot see, because an unrankable child is skipped ' +\n 'there rather than reported.',\n );\n }\n });\n}\n\n/**\n * Every element of every XML part, once.\n *\n * The three rules above each want the same walk. Sharing it means one traversal\n * of the package instead of three, and - more usefully - one place where the\n * decision \"which parts does an order rule apply to\" is made. Relationship\n * parts are excluded: `Relationships` is not in any schema we generate from, so\n * every one of its children would be unrankable and the rules would be checking\n * nothing while appearing to check everything.\n */\nfunction forEachElement(ctx: Context, visit: (part: string, element: XElement) => void): void {\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n for (const element of descendantElements(document.root)) visit(part, element);\n }\n}\n","import { CONTENT_TYPE, isRelationshipPartName } from '@pptx-studio/opc';\nimport {\n attribute,\n childElements,\n descendantElements,\n namespaceOf,\n NS,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation } from '../report/location.js';\n\n/**\n * `V013` … `V017`: children and attributes that are not optional.\n *\n * Every one of these is a `minOccurs` the schema states plainly, and every one\n * is broken the same way: by an editor deleting the last of something. The last\n * paragraph goes and a `p:txBody` is left with no `a:p`; a shape is dragged out\n * of a group and the group's `p:grpSpPr` is dropped with it. That is why these\n * are separate rules from the ordering ones even though a missing child and a\n * misplaced child are both \"the sequence is wrong\": the messages have to say\n * *add this*, not *move this*, and they have to fire on the parent rather than\n * on a child that is not there to point at.\n */\n\n/** The twelve attributes of `CT_ColorMapping`. All required, no defaults. */\nconst CLR_MAP_ATTRIBUTES = [\n 'bg1',\n 'tx1',\n 'bg2',\n 'tx2',\n 'accent1',\n 'accent2',\n 'accent3',\n 'accent4',\n 'accent5',\n 'accent6',\n 'hlink',\n 'folHlink',\n] as const;\n\n/** `p:presentation` carries `p:notesSz`. */\nexport function v013NotesSize(ctx: Context): void {\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n const root = document.root;\n if (root.local !== 'presentation' || namespaceOf(root) !== NS.p) continue;\n\n if (childElements(root).some((child) => child.local === 'notesSz')) continue;\n ctx.add(\n 'V013',\n elementLocation(part, root),\n 'no <p:notesSz>. In CT_Presentation p:sldSz is [0..1] and p:notesSz is [1..1] - the ' +\n 'asymmetry is the whole of this rule, and a generator that treats the two the same way ' +\n 'writes a presentation part that is missing a required child.',\n );\n }\n}\n\n/** `p:clrMap` carries all twelve attributes. */\nexport function v014ColorMap(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'clrMap' || namespaceOf(element) !== NS.p) return;\n const missing = CLR_MAP_ATTRIBUTES.filter((name) => attribute(element, name) === undefined);\n if (missing.length === 0) return;\n ctx.add(\n 'V014',\n elementLocation(part, element),\n 'the colour map is missing ' +\n missing.join(', ') +\n '. All twelve attributes of CT_ColorMapping are required and none has a default; a ' +\n 'partial map is not a map with a gap, it is an invalid element - and it is the element ' +\n 'that decides what bg1 and tx1 resolve to everywhere in the deck.',\n );\n });\n}\n\n/** `p:spTree` begins with `p:nvGrpSpPr` then `p:grpSpPr`. */\nexport function v015ShapeTreePrologue(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'spTree' || namespaceOf(element) !== NS.p) return;\n const children = childElements(element);\n if (children[0]?.local !== 'nvGrpSpPr' || children[1]?.local !== 'grpSpPr') {\n ctx.add(\n 'V015',\n elementLocation(part, element),\n 'a shape tree begins with <nvGrpSpPr> then <grpSpPr>, in that order, before any shape. ' +\n 'This one begins ' +\n (children.length === 0\n ? 'with nothing'\n : children\n .slice(0, 2)\n .map((child) => '<' + child.qname + '>')\n .join(' then ')) +\n '. A shape tree is a group shape, and CT_GroupShape requires both even when the slide ' +\n 'is empty.',\n );\n }\n });\n}\n\n/** Every text body has `a:bodyPr` and at least one `a:p`. */\nexport function v016TextBody(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'txBody') return;\n const children = childElements(element);\n if (!children.some((child) => child.local === 'bodyPr')) {\n ctx.add(\n 'V016',\n elementLocation(part, element),\n '<' + element.qname + '> has no <a:bodyPr>. CT_TextBody requires it first.',\n );\n }\n if (!children.some((child) => child.local === 'p')) {\n ctx.add(\n 'V016',\n elementLocation(part, element),\n '<' +\n element.qname +\n '> has no <a:p>. CT_TextBody is [1..unbounded] paragraphs, and an empty paragraph is ' +\n 'not the same thing as no paragraph - a:endParaRPr is where an empty one gets its ' +\n 'height. This is what deleting the last paragraph in an editor produces.',\n );\n }\n });\n}\n\n/** `p:graphicFrame` carries `p:xfrm` and `a:graphic`. */\nexport function v017GraphicFrame(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'graphicFrame' || namespaceOf(element) !== NS.p) return;\n\n const xfrm = childElements(element).find((child) => child.local === 'xfrm');\n if (xfrm === undefined) {\n ctx.add(\n 'V017',\n elementLocation(part, element),\n 'no <p:xfrm>. Note the namespace: a graphic frame carries the PresentationML transform, ' +\n 'not the a:xfrm every other shape uses. It has no placeholder-inherited geometry path ' +\n 'either, which is why a rebound chart or table gets a copy of its layout transform ' +\n 'rather than having its own deleted.',\n );\n } else if (namespaceOf(xfrm) !== NS.p) {\n ctx.add(\n 'V017',\n elementLocation(part, xfrm),\n 'the transform here is <' +\n xfrm.qname +\n '>, in the DrawingML namespace. CT_GraphicalObjectFrame takes p:xfrm; a:xfrm in its ' +\n 'place is the same element name bound to the wrong schema.',\n );\n }\n\n // By local name and namespace, never by qname: `a:` is the conventional\n // prefix for DrawingML and not a guaranteed one, and a part that binds it\n // differently would silently stop being checked.\n const graphic = childElements(element).find(\n (child) => child.local === 'graphic' && namespaceOf(child) === NS.a,\n );\n if (graphic === undefined) {\n ctx.add(\n 'V017',\n elementLocation(part, element),\n 'no <a:graphic>. The frame is the wrapper; the graphic is the thing in it, and a frame ' +\n 'without one names no table, chart, diagram or OLE object at all.',\n );\n }\n });\n}\n\n/**\n * Presentation-family parts only.\n *\n * A `.pptx` carries whole foreign documents inside it - an embedded workbook\n * behind every chart, a Word document behind some OLE objects - and their parts\n * are XML with elements called `txBody` and `graphicFrame` in namespaces these\n * rules do not govern. Checking them would be applying PresentationML's\n * cardinalities to SpreadsheetML's schema, which is why every rule above tests\n * the namespace and not only the local name, and why the walk itself stops at\n * parts whose content type belongs to another format.\n */\nconst FOREIGN_CONTENT_TYPES = new Set<string>([\n CONTENT_TYPE.spreadsheet,\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml',\n]);\n\nfunction forEachElement(ctx: Context, visit: (part: string, element: XElement) => void): void {\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const contentType = ctx.contentType(part);\n if (contentType !== undefined && FOREIGN_CONTENT_TYPES.has(contentType)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n for (const element of descendantElements(document.root)) visit(part, element);\n }\n}\n\n/** Exported for `refusal-rules.ts`, which walks the same parts for the same reason. */\nexport { forEachElement, FOREIGN_CONTENT_TYPES };\n","import {\n CONTENT_TYPE,\n isRelationshipPartName,\n normalizePartName,\n REL_TYPE,\n} from '@pptx-studio/opc';\nimport {\n attributeValue,\n descendantElements,\n namespaceOf,\n NS,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { attributeLocation, elementLocation } from '../report/location.js';\nimport { bySource, readRelsParts, resolveTarget } from '../rels.js';\n\n/**\n * `V018` … `V021`: four identifier spaces, and never one allocator.\n *\n * A presentation has four kinds of id and they do not share a rule between\n * them. Slide ids start at 256 and stop at 2147483647. Master and layout ids\n * start at 2147483648, and - the part no schema says - come out of **one**\n * counter shared between them. Shape ids are unique inside a part and free to\n * repeat across parts. Placeholder indices are not identifiers at all; they are\n * a join key against another part.\n *\n * Every one of those is a way to break a file that looks like a way to be\n * tidy. Renumbering shape ids to be unique across the deck is the obvious\n * example: it is more consistent, it is what a database would do, and it\n * detaches every `p:custDataLst`, VML `@spid` and animation target that names\n * the old number.\n */\n\nconst SLIDE_ID_MIN = 256;\nconst SLIDE_ID_MAX = 2147483647;\nconst SHEET_ID_MIN = 2147483648;\nconst SHEET_ID_MAX = 4294967295;\n\n/** An `@id` read as a base-10 integer, or `null` when it is not one. */\nfunction integerAttribute(element: XElement, name: string): number | null {\n const raw = attributeValue(element, name);\n if (raw === undefined || !/^\\d+$/.test(raw.trim())) return null;\n return Number(raw.trim());\n}\n\n/** `p:sldId/@id` is 256…2147483647 and unique. */\nexport function v018SlideIds(ctx: Context): void {\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n const seen = new Map<number, XElement>();\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'sldId' || namespaceOf(element) !== NS.p) continue;\n const raw = attributeValue(element, 'id');\n const value = integerAttribute(element, 'id');\n if (value === null) {\n ctx.add(\n 'V018',\n attributeLocation(part, element, 'id'),\n raw === undefined\n ? '<p:sldId> has no @id.'\n : '@id=\"' + raw + '\" is not a base-10 unsigned integer.',\n );\n continue;\n }\n if (value < SLIDE_ID_MIN || value > SLIDE_ID_MAX) {\n ctx.add(\n 'V018',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is outside ST_SlideId, which is ' +\n String(SLIDE_ID_MIN) +\n '…' +\n String(SLIDE_ID_MAX) +\n '. The floor is the part that gets missed: nothing about a first slide suggests its ' +\n 'id should start at 256.',\n );\n }\n if (seen.has(value)) {\n ctx.add(\n 'V018',\n attributeLocation(part, element, 'id'),\n '@id=' + String(value) + ' is used twice in this slide list.',\n );\n } else {\n seen.set(value, element);\n }\n }\n }\n}\n\n/**\n * Master and layout ids share one number space.\n *\n * The uniqueness check runs across the whole package rather than per part,\n * because `p:sldMasterId` lives in `ppt/presentation.xml` and `p:sldLayoutId`\n * lives in each master's own `p:sldLayoutIdLst` - so a collision between the\n * two is invisible to anything that validates one part at a time. That is\n * exactly how `a12-masters` was written wrong: a chassis numbering masters and\n * layouts from two counters is indistinguishable from correct with one master\n * and collides on the second.\n */\nexport function v019SheetIds(ctx: Context): void {\n const seen = new Map<number, string>();\n\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n for (const element of descendantElements(document.root)) {\n const isMaster = element.local === 'sldMasterId';\n const isLayout = element.local === 'sldLayoutId';\n if ((!isMaster && !isLayout) || namespaceOf(element) !== NS.p) continue;\n\n const raw = attributeValue(element, 'id');\n const value = integerAttribute(element, 'id');\n if (value === null) {\n // `@id` is optional on both in the schema. PowerPoint always writes\n // one, and a list entry without one cannot collide with anything, so\n // this is only reported when the attribute is present and unreadable.\n if (raw !== undefined) {\n ctx.add(\n 'V019',\n attributeLocation(part, element, 'id'),\n '@id=\"' + raw + '\" is not a base-10 unsigned integer.',\n );\n }\n continue;\n }\n if (value < SHEET_ID_MIN || value > SHEET_ID_MAX) {\n ctx.add(\n 'V019',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is outside ' +\n (isMaster ? 'ST_SlideMasterId' : 'ST_SlideLayoutId') +\n ', which is ' +\n String(SHEET_ID_MIN) +\n ' and up.',\n );\n continue;\n }\n const previous = seen.get(value);\n if (previous !== undefined) {\n ctx.add(\n 'V019',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is already used by ' +\n previous +\n '. Master and layout ids are one number space, not two: PowerPoint allocates them ' +\n 'from a single running counter - master, its layouts, next master, its layouts - and ' +\n 'refuses a package that does not.',\n );\n } else {\n seen.set(value, '<' + element.qname + '> in ' + part);\n }\n }\n }\n}\n\n/**\n * The `mc:Choice` / `mc:Fallback` ancestors of an element, outermost first.\n *\n * Two shapes in different branches of the same `mc:AlternateContent` never\n * exist in the same document: a consumer picks one branch and the other is not\n * there. So they may carry the same `@id`, and PowerPoint's own writer does\n * exactly that - `a22-chartex` has a `p:graphicFrame` with `id=\"10\"` in the\n * `mc:Choice` and the `p:pic` that stands in for it, also `id=\"10\"`, in the\n * `mc:Fallback`. Reporting that as a duplicate would fire on files PowerPoint\n * wrote, which is the corpus's whole job to prevent.\n */\nfunction branchPath(element: XElement): XElement[] {\n const path: XElement[] = [];\n for (let node = element.parent; node !== undefined; node = node.parent) {\n if (node.local === 'Choice' || node.local === 'Fallback') path.push(node);\n }\n return path.reverse();\n}\n\n/**\n * True when two elements can never both be present.\n *\n * They cannot when their branch paths diverge at some depth *into two branches\n * of the same `mc:AlternateContent`*. Diverging into branches of two different\n * `mc:AlternateContent` elements is not exclusion - both are chosen, and both\n * sets of shapes are on the slide together.\n */\nfunction mutuallyExclusive(a: readonly XElement[], b: readonly XElement[]): boolean {\n const depth = Math.min(a.length, b.length);\n for (let i = 0; i < depth; i++) {\n if (a[i] === b[i]) continue;\n return a[i]!.parent === b[i]!.parent;\n }\n return false;\n}\n\n/**\n * `p:cNvPr/@id` is unique within its part and reads as a positive signed\n * 32-bit integer.\n *\n * PresentationML only, which is narrower than \"every element called `cNvPr`\"\n * and had to be. A SmartArt drawing part writes `dsp:cNvPr id=\"0\"` on every\n * shape it contains - PowerPoint generates those parts and regenerates them on\n * any diagram interaction, so whatever the ids there are for, it is not\n * identity. `a23-smartart` is where that turned up.\n */\nexport function v020ShapeIds(ctx: Context): void {\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n\n const seen = new Map<number, { label: string; branch: XElement[] }[]>();\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'cNvPr' || namespaceOf(element) !== NS.p) continue;\n const raw = attributeValue(element, 'id');\n if (raw === undefined) {\n ctx.add('V020', elementLocation(part, element), '<' + element.qname + '> has no @id.');\n continue;\n }\n const value = integerAttribute(element, 'id');\n if (value === null) {\n ctx.add(\n 'V020',\n attributeLocation(part, element, 'id'),\n '@id=\"' + raw + '\" is not a base-10 unsigned integer.',\n );\n continue;\n }\n // Measured, not read. `ST_DrawingElementId` is `xsd:unsignedInt`, so the\n // schema allows the whole 32-bit range - but 2147483648…4294967294 are\n // whole-package refusals and 4294967295 opens, because PowerPoint reads\n // the attribute as a *signed* 32-bit integer and keeps 0xFFFFFFFF as a\n // sentinel it renumbers away on save. `a39-large-ids` is the deck.\n if (value > SLIDE_ID_MAX && value !== SHEET_ID_MAX) {\n ctx.add(\n 'V020',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is in 2147483648…4294967294, which PowerPoint refuses outright. ST_DrawingElementId ' +\n 'is xsd:unsignedInt and every value up to 2147483647 opens; PowerPoint reads this one ' +\n 'signed. (4294967295 also opens - it is minus one, which PowerPoint keeps as a ' +\n 'sentinel and renumbers away on save.)',\n );\n }\n const branch = branchPath(element);\n const others = seen.get(value) ?? [];\n const clash = others.find((other) => !mutuallyExclusive(other.branch, branch));\n if (clash !== undefined) {\n ctx.add(\n 'V020',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is already used by <' +\n clash.label +\n '> in this part. Shape ids are unique within a part and free to repeat across parts - ' +\n 'renumbering them to be unique across the deck is tidier and detaches every VML ' +\n '@spid and animation target that names the old number.',\n );\n }\n others.push({\n label: element.qname + ' ' + (attributeValue(element, 'name') ?? ''),\n branch,\n });\n seen.set(value, others);\n }\n }\n}\n\n/** A placeholder as the matcher sees it. `null` type means the attribute was absent. */\ninterface Placeholder {\n readonly type: string;\n readonly idx: number;\n readonly element: XElement;\n}\n\n/**\n * `CT_Placeholder` defaults, materialised.\n *\n * `@type` defaults to `body` and `@idx` to `0` in the ECMA-376 schema, and\n * `ctrTitle` normalises to `title` because they are the same slot with\n * different centring. Worth flagging while it is fresh: the plan says\n * `<p:ph/>` means `type=\"obj\"` in sub-phase 2.9 and `type ??= 'body'` in 7.1,\n * and those cannot both be right. The schema says `body`, so that is what this\n * rule uses - and it is one of the reasons the rule is a warning rather than\n * fatal. Sub-phase 7.1 settles it against the 121-case matrix.\n */\nfunction placeholdersOf(root: XElement): Placeholder[] {\n const out: Placeholder[] = [];\n for (const element of descendantElements(root)) {\n if (element.local !== 'ph' || namespaceOf(element) !== NS.p) continue;\n const rawType = attributeValue(element, 'type') ?? 'body';\n const type = rawType === 'ctrTitle' ? 'title' : rawType;\n const idx = Number(attributeValue(element, 'idx') ?? '0');\n out.push({ type, idx: Number.isFinite(idx) ? idx : 0, element });\n }\n return out;\n}\n\n/** Types matched on type alone, ignoring `@idx`. See tier 3. */\nconst TYPE_ONLY = new Set(['sldNum', 'dt', 'ftr', 'hdr']);\n\n/** The five tiers, in order. Returns the matching layout placeholder, or `null`. */\nfunction matchInLayout(slide: Placeholder, layout: readonly Placeholder[]): Placeholder | null {\n const exact = layout.find((ph) => ph.type === slide.type && ph.idx === slide.idx);\n if (exact !== undefined) return exact;\n if (slide.type === 'title') {\n const anyTitle = layout.find((ph) => ph.type === 'title');\n if (anyTitle !== undefined) return anyTitle;\n }\n if (TYPE_ONLY.has(slide.type)) {\n const byType = layout.find((ph) => ph.type === slide.type);\n if (byType !== undefined) return byType;\n }\n if (slide.type === 'body') {\n const bodies = layout.filter((ph) => ph.type === 'body');\n if (bodies.length === 1) return bodies[0]!;\n }\n return null;\n}\n\n/**\n * Every slide placeholder finds a counterpart in its layout.\n *\n * A warning, and the reason matters: PowerPoint opens the file. A `p:ph` that\n * matches nothing inherits nothing - no geometry, no text style, no prompt -\n * and the shape is drawn wherever the renderer can work out, which is a deck\n * that is silently wrong rather than a deck that is refused. Refusing an export\n * over it would block a user from saving a file that already opened fine\n * everywhere, which is the failure mode a validator has to avoid most.\n */\nexport function v021PlaceholderIndices(ctx: Context): void {\n const relsBySource = bySource(readRelsParts(ctx));\n\n for (const part of ctx.parts()) {\n if (ctx.contentType(part) !== CONTENT_TYPE.slide) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n\n const rels = relsBySource.get(normalizePartName(part));\n const layoutRel = (rels?.relationships ?? []).find((rel) => rel.type === REL_TYPE.slideLayout);\n if (layoutRel === undefined) continue; // `V009` has already said so.\n const layoutPart = resolveTarget(rels!.source, layoutRel.target).part;\n if (layoutPart === null) continue;\n const layoutDocument = ctx.document(layoutPart);\n if (layoutDocument === null) continue;\n\n const layout = placeholdersOf(layoutDocument.root);\n for (const slidePh of placeholdersOf(document.root)) {\n if (matchInLayout(slidePh, layout) !== null) continue;\n ctx.add(\n 'V021',\n elementLocation(part, slidePh.element),\n 'placeholder (type=' +\n slidePh.type +\n ', idx=' +\n String(slidePh.idx) +\n ') matches nothing in ' +\n layoutPart +\n ', which offers ' +\n (layout.length === 0\n ? 'none'\n : layout.map((ph) => ph.type + '/' + String(ph.idx)).join(', ')) +\n '. An unmatched placeholder inherits no geometry and no text style.',\n );\n }\n }\n}\n","import { CONTENT_TYPE } from '@pptx-studio/opc';\nimport {\n attribute,\n attributeValue,\n childElements,\n descendantElements,\n namespaceOf,\n NS,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { attributeLocation, elementLocation } from '../report/location.js';\nimport { forEachElement } from './required.js';\n\n/**\n * `V022` … `V026`: schema-legal markup PowerPoint refuses.\n *\n * This is the category that justifies the package. Nothing here can be derived\n * from ECMA-376; every rule is the record of a package built with one change in\n * it, opened, and declined - \"PowerPoint could not open the file\", or\n * `0x80070570`, \"the file or directory is corrupted and unreadable\". No log, no\n * part named, no line number. Sub-phase 1.5's `cli bisect` exists because that\n * is the entire diagnostic channel, and these five rules are what it found\n * before it existed, by hand.\n *\n * Which means each of them is falsifiable in a way the schema rules are not: if\n * a later PowerPoint build opens one of these, the rule is wrong and should be\n * deleted. The `why` in `rules.ts` records what was tried and what opened, so\n * that the person who deletes it knows what they are contradicting.\n */\n\n/** Parts where `hdr` and `sldImg` placeholders are legal - they belong to these families. */\nconst NOTES_FAMILY = new Set<string>([\n CONTENT_TYPE.notesSlide,\n CONTENT_TYPE.notesMaster,\n CONTENT_TYPE.handoutMaster,\n]);\n\n/** `p:ph/@type` is not `hdr` or `sldImg` on a slide, layout or master. */\nexport function v022PlaceholderType(ctx: Context): void {\n for (const part of ctx.parts()) {\n const contentType = ctx.contentType(part);\n if (contentType === undefined || NOTES_FAMILY.has(contentType)) continue;\n if (\n contentType !== CONTENT_TYPE.slide &&\n contentType !== CONTENT_TYPE.slideLayout &&\n contentType !== CONTENT_TYPE.slideMaster\n ) {\n continue;\n }\n const document = ctx.document(part);\n if (document === null) continue;\n\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'ph' || namespaceOf(element) !== NS.p) continue;\n const type = attributeValue(element, 'type');\n if (type !== 'hdr' && type !== 'sldImg') continue;\n ctx.add(\n 'V022',\n attributeLocation(part, element, 'type'),\n 'type=\"' +\n type +\n '\" is a whole-package refusal here, alone and with no other change. The other seven ' +\n 'content types were built as one-type packages in the same bisection and every one ' +\n 'opens: obj, chart, tbl, clipArt, dgm, media, pic. Nothing in the schema says so - ' +\n 'CT_Placeholder is one complex type shared by every sheet family and ' +\n 'ST_PlaceholderType is one enumeration holding all sixteen values - but hdr and ' +\n 'sldImg belong to the notes and handout families and PowerPoint enforces it.',\n );\n }\n }\n}\n\n/**\n * The built-in geometry guides.\n *\n * Deliberately generous, and deliberately temporary. The authoritative table is\n * sub-phase 2.2's - forty-four seeded guides beside the seventeen `fmla`\n * operators - and it belongs in `@pptx-studio/geometry` rather than here. Until\n * it exists this list plus the two shape tests below stand in for it.\n *\n * Generous in the safe direction on purpose. This rule is fatal, so a name we\n * wrongly think is undefined refuses a file that works, while a name we wrongly\n * accept only means we miss one instance of a defect whose real-world form is a\n * typo or a deleted `a:gd` - and neither of those looks anything like `wd12`.\n */\nconst BUILTIN_GUIDES = new Set([\n '3cd4',\n '3cd8',\n '5cd8',\n '7cd8',\n 'b',\n 'cd2',\n 'cd4',\n 'cd8',\n 'h',\n 'hc',\n 'hd2',\n 'hd3',\n 'hd4',\n 'hd5',\n 'hd6',\n 'hd8',\n 'l',\n 'ls',\n 'r',\n 'ss',\n 'ssd2',\n 'ssd4',\n 'ssd6',\n 'ssd8',\n 'ssd16',\n 'ssd32',\n 't',\n 'vc',\n 'w',\n 'wd2',\n 'wd3',\n 'wd4',\n 'wd5',\n 'wd6',\n 'wd8',\n 'wd10',\n 'wd32',\n]);\n\n/** `wd12`, `hd10`, `ssd12` - the same shape as a built-in, with a divisor we did not list. */\nconst BUILTIN_SHAPED = /^(?:w|h|ss|ls)d\\d+$/;\n/** `2cd4`, `5cd8` - a fraction of a full circle. */\nconst ANGLE_SHAPED = /^\\d+cd\\d+$/;\n\n/** A literal number, in EMU or in 60000ths of a degree. Both may be negative. */\nconst LITERAL = /^-?\\d+$/;\n\nfunction isDefinedGuide(name: string, defined: ReadonlySet<string>): boolean {\n if (name === '' || LITERAL.test(name)) return true;\n if (defined.has(name) || BUILTIN_GUIDES.has(name)) return true;\n return BUILTIN_SHAPED.test(name) || ANGLE_SHAPED.test(name);\n}\n\n/** Attributes that hold a guide name rather than a value of their own. */\nconst GUIDE_VALUED: Readonly<Record<string, readonly string[]>> = {\n pt: ['x', 'y'],\n pos: ['x', 'y'],\n rect: ['l', 't', 'r', 'b'],\n ahXY: ['minX', 'maxX', 'minY', 'maxY', 'gdRefX', 'gdRefY'],\n ahPolar: ['minAng', 'maxAng', 'minR', 'maxR', 'gdRefAng', 'gdRefR'],\n cxn: ['ang'],\n arcTo: ['wR', 'hR', 'stAng', 'swAng'],\n};\n\n/**\n * Every geometry guide named is a guide that is defined.\n *\n * Scoped to one `a:custGeom` or `a:prstGeom` at a time, because that is the\n * scope a guide has: `adj1` in one shape has nothing to do with `adj1` in the\n * next. A `prstGeom`'s guides come from the preset definition rather than from\n * the markup, so only its `a:avLst` is checked - which is the whole of what a\n * preset shape can get wrong from here, and is exactly what dragging an adjust\n * handle writes.\n */\nexport function v023GeometryGuides(ctx: Context): void {\n forEachElement(ctx, (part, geometry) => {\n const isCustom = geometry.local === 'custGeom';\n if ((!isCustom && geometry.local !== 'prstGeom') || namespaceOf(geometry) !== NS.a) return;\n\n const defined = new Set<string>();\n for (const element of descendantElements(geometry)) {\n if (element.local !== 'gd') continue;\n const name = attributeValue(element, 'name');\n if (name !== undefined && name !== '') defined.add(name);\n }\n\n for (const element of descendantElements(geometry)) {\n if (element.local === 'gd') {\n // `fmla=\"*/ w adj1 100000\"` - the operator, then two or three\n // arguments, each a guide name or a literal.\n const formula = attributeValue(element, 'fmla');\n if (formula === undefined) continue;\n const args = formula.trim().split(/\\s+/).slice(1);\n for (const arg of args) {\n if (isDefinedGuide(arg, defined)) continue;\n report(ctx, part, element, 'fmla', arg, defined);\n }\n continue;\n }\n const names = GUIDE_VALUED[element.local];\n if (names === undefined || namespaceOf(element) !== NS.a) continue;\n for (const attributeName of names) {\n const value = attribute(element, attributeName);\n if (value === undefined || isDefinedGuide(value.value, defined)) continue;\n report(ctx, part, element, attributeName, value.value, defined);\n }\n }\n });\n}\n\nfunction report(\n ctx: Context,\n part: string,\n element: XElement,\n attributeName: string,\n name: string,\n defined: ReadonlySet<string>,\n): void {\n ctx.add(\n 'V023',\n attributeLocation(part, element, attributeName),\n '\"' +\n name +\n '\" names a guide nothing defines. This geometry defines ' +\n (defined.size === 0 ? 'none' : [...defined].sort().join(', ')) +\n '. ST_GeomGuideName is an unconstrained token, so nothing in the schema forbids it - and ' +\n 'a package containing it is refused outright, not repaired and not drawn without the shape.',\n );\n}\n\n/** The chart namespace, for `V024`. */\nconst CHART_NS = 'http://schemas.openxmlformats.org/drawingml/2006/chart';\n\n/**\n * A series' `c:tx` holds `c:strRef` or `c:v`, and nothing else.\n *\n * Scoped to `c:ser/c:tx` rather than to every `c:tx`, and the distinction is\n * real: a series' text is `CT_SerTx`, a choice of `c:strRef` or `c:v`, while a\n * title's or a data label's `c:tx` is `CT_Tx`, a choice of `c:strRef` or\n * `c:rich`. Checking both with one list would refuse every chart title in the\n * corpus.\n */\nexport function v024SeriesText(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'tx' || namespaceOf(element) !== CHART_NS) return;\n const parent = element.parent;\n if (parent === undefined || parent.local !== 'ser' || namespaceOf(parent) !== CHART_NS) return;\n\n for (const child of childElements(element)) {\n if (child.local === 'strRef' || child.local === 'v') continue;\n ctx.add(\n 'V024',\n elementLocation(part, child),\n '<' +\n child.qname +\n '> inside a series <' +\n element.qname +\n '>. CT_SerTx is a choice of c:strRef or c:v and nothing else. The trap is that c:cat ' +\n 'and c:val, two elements away in the same series, both accept the literal forms - so ' +\n 'a c:strLit here looks like markup that ought to work, and it is a whole-package ' +\n 'refusal.',\n );\n }\n });\n}\n\n/** No `p:control`. */\nexport function v025Control(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'control' || namespaceOf(element) !== NS.p) return;\n ctx.add(\n 'V025',\n elementLocation(part, element),\n 'a <p:control> is a whole-package refusal in all eight forms tried: bare, name-only, with ' +\n 'and without r:id, with a p:pic preview, with an ActiveX part and its .bin, and inside a ' +\n 'macro-enabled package. An empty <p:controls> is accepted, which places the refusal ' +\n 'precisely on this element.',\n );\n });\n}\n\n/** The chart-style namespace and its thirty-one entries. */\nconst CHART_STYLE_NS = 'http://schemas.microsoft.com/office/drawing/2012/chartStyle';\n\nconst CHART_STYLE_ENTRIES = [\n 'axisTitle',\n 'categoryAxis',\n 'chartArea',\n 'dataLabel',\n 'dataLabelCallout',\n 'dataPoint',\n 'dataPoint3D',\n 'dataPointLine',\n 'dataPointMarker',\n 'dataPointMarkerLayout',\n 'dataPointWireframe',\n 'dataTable',\n 'downBar',\n 'dropLine',\n 'errorBar',\n 'floor',\n 'gridlineMajor',\n 'gridlineMinor',\n 'hiLoLine',\n 'leaderLine',\n 'legend',\n 'plotArea',\n 'plotArea3D',\n 'seriesAxis',\n 'seriesLine',\n 'title',\n 'trendline',\n 'trendlineLabel',\n 'upBar',\n 'valueAxis',\n 'wall',\n] as const;\n\n/**\n * A `cs:chartStyle` carries all thirty-one of its entries.\n *\n * The shape of this finding is the interesting half. A chart with **no**\n * chart-style relationship at all opens; a chart whose style part is present\n * and has four of thirty-one does not. So the rule is not \"the part is\n * required\", it is \"if the part exists it must be complete\" - a subset is worse\n * than an absence, which is the opposite of what any partial-styling model\n * would predict, and is why we found it by shipping four entries rather than by\n * reasoning.\n */\nexport function v026ChartStyleComplete(ctx: Context): void {\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n const root = document.root;\n if (root.local !== 'chartStyle' || namespaceOf(root) !== CHART_STYLE_NS) continue;\n\n const present = new Set(childElements(root).map((child) => child.local));\n const missing = CHART_STYLE_ENTRIES.filter((name) => !present.has(name));\n if (missing.length === 0) continue;\n ctx.add(\n 'V026',\n elementLocation(part, root),\n 'a chart style with ' +\n String(CHART_STYLE_ENTRIES.length - missing.length) +\n ' of its ' +\n String(CHART_STYLE_ENTRIES.length) +\n ' entries. Missing: ' +\n missing.join(', ') +\n '. Four entries were refused and thirty-one opened; a chart with no chart-style ' +\n 'relationship at all is fine.',\n );\n }\n}\n","import { isRelationshipPartName } from '@pptx-studio/opc';\nimport {\n attributeValue,\n descendantElements,\n sourceOf,\n textContent,\n type XDocument,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation, partLocation, xpathOf } from '../report/location.js';\n\n/**\n * `V027` … `V029`: what has to come back out unchanged.\n *\n * These are the rules the architecture exists for. Preserving charts, SmartArt,\n * animations, OLE objects and macros is unachievable in any design where the\n * writer has to *understand* a feature in order to emit it - and the moment\n * preservation is a feature rather than the default state, it is a feature with\n * a coverage percentage, and the percentage is never a hundred.\n *\n * So the default is that nothing changes, and these three rules are where that\n * intention becomes falsifiable.\n *\n * ## They need two packages, and they say so when they only have one\n *\n * All three compare against the package as it was opened. Asked to validate a\n * file with no history - `pptx-studio validate deck.pptx`, a deck somebody\n * dropped on a page - there is nothing to compare against and they do not run.\n * The report lists them under `skipped` with that reason, because a\n * preservation rule that reports nothing because it had nothing to compare\n * against looks exactly like one that found nothing, and those are opposite\n * answers.\n */\n\n/** `ppt/embeddings/…` - OLE2/CFB compound files. Never ours to rewrite. */\nfunction isEmbedding(part: string): boolean {\n return /^\\/ppt\\/embeddings\\//i.test(part);\n}\n\n/**\n * A part nobody edited comes back out byte for byte.\n *\n * \"Nobody edited\" is `PartInfo.fromArchive`, the store's own record of whether a\n * part's bytes still come from the archive it was opened from - not a byte\n * comparison, which could not tell an edit that happened to produce identical\n * bytes from no edit at all. The rule then checks the converse: a part the store\n * says is untouched really is identical.\n *\n * That is not circular, because the two facts come from different places. The\n * flag is set by whoever called `replacePart`; the bytes come from whatever the\n * writer actually emitted. A writer that re-serialised a clean part - the exact\n * failure this rule exists for - would leave the flag alone and change the\n * bytes, and this is where the two stop agreeing.\n */\nexport function v027UneditedPartsUnchanged(ctx: Context): void {\n const baseline = ctx.baseline;\n if (baseline === null) return;\n\n for (const part of ctx.parts()) {\n const before = ctx.baselineRead(part);\n if (before === null) continue; // Added this session. Nothing to preserve.\n\n const embedding = isEmbedding(part);\n if (embedding && ctx.edited(part)) {\n ctx.add(\n 'V027',\n partLocation(part),\n 'an OLE embedding was replaced. ppt/embeddings/*.bin are OLE2/CFB compound files and any ' +\n 'rewrite of one is a guaranteed repair prompt - we render their preview and never ' +\n 'touch the object.',\n );\n continue;\n }\n if (!embedding && ctx.edited(part)) continue; // Edited on purpose.\n\n const after = ctx.read(part);\n if (after === null) continue;\n if (sameBytes(before, after)) continue;\n\n ctx.add(\n 'V027',\n partLocation(part),\n 'nobody edited this part and its bytes changed anyway (' +\n String(before.byteLength) +\n ' bytes in, ' +\n String(after.byteLength) +\n ' out). A part that was not edited is streamed through, never re-serialised: the ' +\n 'moment that stops being true, every feature we cannot parse is a feature we can lose.',\n );\n }\n}\n\nfunction sameBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false;\n for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** Local names of the containers held opaque, with the namespace-free test that finds them. */\nfunction isOpaqueContainer(element: XElement): boolean {\n // `mc:AlternateContent` by local name, because the `mc` prefix is only a\n // convention; `a:ext` and `p:ext` likewise. The namespace is not checked\n // because the point is to be *broader* than the schemas we know - an\n // extension container from a vocabulary we have never read is exactly the\n // thing this rule protects.\n return element.local === 'AlternateContent' || element.local === 'ext';\n}\n\n/** Every opaque container in a document, as its exact source text. */\nfunction opaqueSources(document: XDocument): { element: XElement; source: string }[] {\n const out: { element: XElement; source: string }[] = [];\n for (const element of descendantElements(document.root)) {\n if (!isOpaqueContainer(element)) continue;\n out.push({ element, source: sourceOf(document, element) });\n }\n return out;\n}\n\n/**\n * No `mc:AlternateContent` branch and no extension was rebuilt.\n *\n * The check is a multiset test, not a positional one: every opaque container in\n * the part we are about to write must appear, character for character,\n * somewhere in the part as it was opened. That formulation is deliberate.\n *\n * A positional comparison - same XPath, same text - would be exact and would\n * also fire every time a shape was inserted above one, because the index in the\n * path shifts. The multiset test cannot be fooled in the direction that matters\n * (text nobody wrote before is text we wrote) and is immune to the reordering\n * that is a normal, permitted edit.\n *\n * **Deletion is not this rule's business.** An extension can leave because the\n * shape holding it was deleted, and that is a document operation the user asked\n * for. What must never happen is markup *appearing* here that we composed:\n * `mc:Choice/@Requires` names a prefix rather than a URI, so a rewritten branch\n * is how ignorable extension markup becomes a hard error - and `a34-extlst`\n * measured that PowerPoint carries an unknown `a:ext/@uri` through untouched,\n * so an extension we rebuild is one the file would otherwise have kept for ever.\n */\nexport function v028OpaqueContainersUnchanged(ctx: Context): void {\n if (ctx.baseline === null) return;\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part) || !ctx.edited(part)) continue;\n const after = ctx.document(part);\n const before = ctx.baselineDocument(part);\n if (after === null || before === null) continue;\n\n const known = new Set(opaqueSources(before).map((entry) => entry.source));\n for (const entry of opaqueSources(after)) {\n if (known.has(entry.source)) continue;\n const uri = attributeValue(entry.element, 'uri');\n ctx.add(\n 'V028',\n elementLocation(part, entry.element),\n '<' +\n entry.element.qname +\n '>' +\n (uri === undefined ? '' : ' uri=\"' + uri + '\"') +\n ' is not markup this part arrived with. These containers are carried through ' +\n 'byte for byte and never composed: we do not know what is in them, which is the ' +\n 'whole reason they are held opaque.',\n );\n }\n }\n}\n\n/** An `a:fld` and the two things about it that must survive. */\ninterface Field {\n readonly id: string;\n readonly text: string;\n readonly element: XElement;\n}\n\nfunction fieldsOf(root: XElement): Field[] {\n const out: Field[] = [];\n for (const element of descendantElements(root)) {\n if (element.local !== 'fld') continue;\n out.push({\n id: attributeValue(element, 'id') ?? '',\n text: textContent(element),\n element,\n });\n }\n return out;\n}\n\n/** `a:t` elements whose `xml:space` was declared, keyed by path. */\nfunction spacePreserved(root: XElement): Map<string, XElement> {\n const out = new Map<string, XElement>();\n for (const element of descendantElements(root)) {\n if (element.local !== 't') continue;\n if (attributeValue(element, 'xml:space') !== 'preserve') continue;\n out.set(xpathOf(element), element);\n }\n return out;\n}\n\n/** The path of every `a:t`, so \"is this one still there\" is a set lookup. */\nfunction textPaths(root: XElement): Set<string> {\n const out = new Set<string>();\n for (const element of descendantElements(root)) {\n if (element.local === 't') out.add(xpathOf(element));\n }\n return out;\n}\n\n/**\n * Text and field identity survive an edit.\n *\n * Three small, separately silent losses.\n *\n * **`xml:space=\"preserve\"` is preserved, not required.** The distinction is\n * measured: 120 `<a:t>` elements in the corpus carry leading or trailing\n * whitespace *without* the attribute and PowerPoint round-trips every one of\n * them with the whitespace intact, so a rule that demanded the attribute would\n * fire on real files that work. What is not allowed is dropping one that was\n * there, because then the attribute's absence starts meaning something it did\n * not mean before.\n *\n * **`a:fld/@id` is a required `ST_Guid`** identifying the field across saves.\n * Regenerating one can make PowerPoint repair the file, and a repair is the one\n * outcome this whole package exists to prevent.\n *\n * **A field's cached `a:t` is its only rendering** anywhere we cannot evaluate\n * the field ourselves. Discarding it turns a date placeholder into an empty box\n * on every consumer that is not PowerPoint - including, for anything we have\n * not implemented, us.\n */\nexport function v029TextAndFieldIdentity(ctx: Context): void {\n if (ctx.baseline === null) return;\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part) || !ctx.edited(part)) continue;\n const after = ctx.document(part);\n const before = ctx.baselineDocument(part);\n if (after === null || before === null) continue;\n\n // xml:space, by path. A path that no longer exists is a deletion and not\n // this rule's business; a path that still exists and has lost the attribute\n // is a rewrite that changed what the text means.\n //\n // Both sets are built once. The obvious shape - scan the new document for\n // each old path - is quadratic in the number of `<a:t>` elements, and a\n // slide with a thousand runs is an ordinary slide.\n const afterSpace = spacePreserved(after.root);\n const afterPaths = textPaths(after.root);\n for (const [path, element] of spacePreserved(before.root)) {\n if (afterSpace.has(path)) continue;\n if (!afterPaths.has(path)) continue;\n ctx.add(\n 'V029',\n { part, xpath: path, offset: element.start },\n 'this <' +\n element.qname +\n '> arrived with xml:space=\"preserve\" and no longer has it. The attribute is not ' +\n 'required - 120 elements in our corpus carry edge whitespace without it - but dropping ' +\n 'one that was written changes what the text is.',\n );\n }\n\n const afterFields = fieldsOf(after.root);\n const beforeById = new Map(fieldsOf(before.root).map((field) => [field.id, field]));\n const beforeIds = new Set(beforeById.keys());\n\n for (const field of afterFields) {\n if (beforeIds.has(field.id)) {\n const original = beforeById.get(field.id)!;\n if (original.text !== '' && field.text.trim() === '') {\n ctx.add(\n 'V029',\n elementLocation(part, field.element),\n 'field ' +\n field.id +\n ' has lost its cached text (\"' +\n original.text +\n '\"). The cache is what renders anywhere the field cannot be evaluated, which ' +\n 'includes every consumer that is not PowerPoint.',\n );\n }\n continue;\n }\n ctx.add(\n 'V029',\n elementLocation(part, field.element),\n 'field id=\"' +\n field.id +\n '\" is not one this part arrived with. a:fld/@id is a required ST_Guid identifying the ' +\n 'field across saves; regenerating one can make PowerPoint repair the file. The ids ' +\n 'that were here: ' +\n (beforeIds.size === 0 ? 'none' : [...beforeIds].join(', ')) +\n '.',\n );\n }\n }\n}\n","import { PartStore, readZip, type ReadZipOptions, type ZipArchive } from '@pptx-studio/opc';\nimport { createContext, type Context, type RuntimeContext } from './context.js';\nimport { ValidateError } from './errors.js';\nimport {\n v001ContentTypeCoverage,\n v002ContentTypeMap,\n v003ArchiveShape,\n v004PartNames,\n v005MainPart,\n} from './rules/package.js';\nimport {\n v006ReferencesResolve,\n v007RelationshipIds,\n v008TargetsResolve,\n v009RequiredEdges,\n} from './rules/relationships.js';\nimport { v010SchemaOrder, v011ExtLstLast, v012UnexpectedChild } from './rules/order.js';\nimport {\n v013NotesSize,\n v014ColorMap,\n v015ShapeTreePrologue,\n v016TextBody,\n v017GraphicFrame,\n} from './rules/required.js';\nimport { v018SlideIds, v019SheetIds, v020ShapeIds, v021PlaceholderIndices } from './rules/id.js';\nimport {\n v022PlaceholderType,\n v023GeometryGuides,\n v024SeriesText,\n v025Control,\n v026ChartStyleComplete,\n} from './rules/refusal.js';\nimport {\n v027UneditedPartsUnchanged,\n v028OpaqueContainersUnchanged,\n v029TextAndFieldIdentity,\n} from './rules/preservation.js';\nimport {\n buildReport,\n findingKey,\n type Finding,\n type Report,\n type SkippedRule,\n} from './report/report.js';\nimport { ruleById, RULE_IDS, type RuleId } from './rules/rules.js';\n\n/**\n * The twenty-nine, wired to their implementations.\n *\n * A plain table, so that \"is every rule reachable\" is a thing a test can ask\n * rather than a thing a reader has to believe. `rules.test.ts` asserts that the\n * keys here are exactly `RULE_IDS` - a rule with a definition and no function\n * would otherwise sit in the table looking enforced.\n */\nconst IMPLEMENTATIONS: Readonly<Record<RuleId, (ctx: Context) => void>> = {\n V001: v001ContentTypeCoverage,\n V002: v002ContentTypeMap,\n V003: v003ArchiveShape,\n V004: v004PartNames,\n V005: v005MainPart,\n V006: v006ReferencesResolve,\n V007: v007RelationshipIds,\n V008: v008TargetsResolve,\n V009: v009RequiredEdges,\n V010: v010SchemaOrder,\n V011: v011ExtLstLast,\n V012: v012UnexpectedChild,\n V013: v013NotesSize,\n V014: v014ColorMap,\n V015: v015ShapeTreePrologue,\n V016: v016TextBody,\n V017: v017GraphicFrame,\n V018: v018SlideIds,\n V019: v019SheetIds,\n V020: v020ShapeIds,\n V021: v021PlaceholderIndices,\n V022: v022PlaceholderType,\n V023: v023GeometryGuides,\n V024: v024SeriesText,\n V025: v025Control,\n V026: v026ChartStyleComplete,\n V027: v027UneditedPartsUnchanged,\n V028: v028OpaqueContainersUnchanged,\n V029: v029TextAndFieldIdentity,\n};\n\n/** Rules that cannot run without the archive bytes. See `Context.archive`. */\nconst ARCHIVE_RULES: readonly RuleId[] = ['V003'];\n\nexport interface ValidateOptions {\n /**\n * The package about to be handed over.\n *\n * On an export this is the store the writer emitted from, **not** a store\n * re-opened from the written bytes. The difference is `V027`: a re-opened\n * store thinks every part came from the archive, so the one rule that asks\n * \"did anything change that nobody edited\" would have no history to ask\n * about and would answer yes about every deliberate edit.\n */\n readonly store?: PartStore;\n /**\n * The archive, when the caller has it.\n *\n * Required for `V003` and for the duplicate half of `V002` - a duplicate\n * `<Default>` is visible only in the markup, because the parsed content-type\n * map collapses one that agrees with itself. Given a `store` and no `bytes`,\n * those are skipped and the report says so.\n */\n readonly bytes?: Uint8Array;\n /** The package as it was opened. The six preservation rules need it. */\n readonly baseline?: PartStore;\n /** The baseline's archive, so an inherited `V003` can be recognised as inherited. */\n readonly baselineBytes?: Uint8Array;\n /** A subset to run. Defaults to all twenty-nine. */\n readonly rules?: readonly RuleId[];\n /** Passed to `readZip` when `bytes` are given. */\n readonly zip?: ReadZipOptions;\n}\n\nfunction openArchive(\n bytes: Uint8Array | undefined,\n zip: ReadZipOptions | undefined,\n): ZipArchive | null {\n if (bytes === undefined) return null;\n try {\n return readZip(bytes, zip ?? {});\n } catch {\n // The store below will fail on the same bytes and say so with a code. A\n // second, worse-worded copy of that message helps nobody.\n return null;\n }\n}\n\n/**\n * Check a package against the rules.\n *\n * Never throws for anything it finds - a broken package produces a report with\n * findings in it, which is the shape a caller can render. It throws only when\n * it was handed something it cannot open at all.\n */\nexport function validatePackage(options: ValidateOptions): Report {\n const archive = openArchive(options.bytes, options.zip);\n const store = options.store ?? openStore(options);\n\n const requested = resolveRules(options.rules);\n const skipped: SkippedRule[] = [];\n const running: RuleId[] = [];\n\n for (const id of requested) {\n const rule = ruleById(id)!;\n if (rule.needsBaseline === true && options.baseline === undefined) {\n skipped.push({\n rule: id,\n why:\n 'it compares against the package as it was opened, and none was supplied. ' +\n 'A preservation rule with nothing to compare against reports nothing, which looks ' +\n 'exactly like finding nothing.',\n });\n continue;\n }\n if (ARCHIVE_RULES.includes(id) && archive === null) {\n skipped.push({\n rule: id,\n why: 'it reads the archive itself, and only a PartStore was supplied.',\n });\n continue;\n }\n running.push(id);\n }\n\n const ctx = createContext({\n store,\n bytes: options.bytes ?? null,\n archive,\n baseline: options.baseline ?? null,\n });\n run(ctx, running);\n\n const findings = attributeOrigins(ctx, options, running);\n\n return buildReport({\n findings,\n checked: running,\n skipped,\n problems: ctx.problems,\n });\n}\n\nfunction openStore(options: ValidateOptions): PartStore {\n if (options.bytes === undefined) {\n throw new ValidateError(\n 'ERR_UNVALIDATABLE',\n 'validatePackage needs either a `store` or the archive `bytes`; it was given neither.',\n );\n }\n try {\n return PartStore.open(options.bytes, options.zip);\n } catch (error) {\n throw new ValidateError(\n 'ERR_UNVALIDATABLE',\n 'the package could not be opened, so there is nothing to validate: ' +\n (error instanceof Error ? error.message : String(error)),\n );\n }\n}\n\nfunction resolveRules(requested: readonly RuleId[] | undefined): readonly RuleId[] {\n if (requested === undefined) return RULE_IDS;\n for (const id of requested) {\n if (ruleById(id) === undefined) {\n throw new ValidateError('ERR_UNKNOWN_RULE', 'there is no rule ' + id, { rule: id });\n }\n }\n // Run in table order whatever order the caller asked in, so a report reads\n // the same way however it was produced.\n return RULE_IDS.filter((id) => requested.includes(id));\n}\n\nfunction run(ctx: RuntimeContext, rules: readonly RuleId[]): void {\n for (const id of rules) IMPLEMENTATIONS[id](ctx);\n}\n\n/**\n * Decide, for each finding, whether we introduced it.\n *\n * The second pass is the whole of it: run the same rules against the package as\n * it was opened and difference the two sets. A finding in both was already\n * there. See `report.ts` for why that question is the one that decides whether\n * an export is refused, and why answering it by differencing beats answering it\n * per rule.\n *\n * Three properties make it cheap enough to be unconditional in the only case\n * that matters. It runs **only when something fatal was found**, so a clean\n * export - which is nearly all of them - pays nothing. It runs **only the rules\n * that fired**, not all twenty-nine. And it skips the preservation rules, which\n * would be comparing the baseline against itself and would find nothing by\n * construction.\n */\nfunction attributeOrigins(\n ctx: RuntimeContext,\n options: ValidateOptions,\n running: readonly RuleId[],\n): readonly Finding[] {\n const baseline = options.baseline;\n if (baseline === undefined) return ctx.findings;\n\n const fatal = ctx.findings.filter((finding) => finding.severity === 'fatal');\n if (fatal.length === 0) {\n return ctx.findings.map((finding) => ({ ...finding, origin: 'introduced' as const }));\n }\n\n const firedRules = new Set(fatal.map((finding) => finding.rule));\n const replay = running.filter((id) => firedRules.has(id) && ruleById(id)!.needsBaseline !== true);\n\n const before = createContext({\n store: baseline,\n bytes: options.baselineBytes ?? null,\n archive: openArchive(options.baselineBytes, options.zip),\n baseline: null,\n });\n run(before, replay);\n const inherited = new Set(before.findings.map(findingKey));\n\n return ctx.findings.map((finding) => ({\n ...finding,\n origin: inherited.has(findingKey(finding)) ? ('inherited' as const) : ('introduced' as const),\n }));\n}\n\n/**\n * Validate, and refuse to go on if we broke something.\n *\n * The one call an export path makes. It throws rather than returning a boolean\n * because the failure has to be impossible to ignore: PowerPoint emits no\n * diagnostic log, its refusal message names no part and no line, and a user who\n * gets a repair prompt has no way at all to find out why. This is the only\n * feedback loop that exists, and a caller who forgot to check a return value\n * would have removed it.\n */\nexport function assertValid(options: ValidateOptions): Report {\n const report = validatePackage(options);\n if (report.ok) return report;\n const blocking = report.findings.filter(\n (finding) => finding.severity === 'fatal' && finding.origin !== 'inherited',\n );\n throw new ValidateError(\n 'ERR_VALIDATION_FAILED',\n 'refusing to hand over the package: ' +\n String(report.blocking) +\n ' fatal finding(s) this session introduced. First: ' +\n blocking[0]!.rule +\n ' at ' +\n blocking[0]!.where.part +\n (blocking[0]!.where.xpath === null ? '' : ' ' + blocking[0]!.where.xpath) +\n ' - ' +\n blocking[0]!.message,\n { part: blocking[0]!.where.part, report },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["#documents","#baselineDocuments","#parts","#parse","#contentTypesDocument","forEachElement"],"sources":["../src/errors.ts","../src/rules/rules.ts","../src/report/report.ts","../src/report/location.ts","../src/context.ts","../src/rels.ts","../src/rules/package.ts","../src/rules/relationships.ts","../src/rules/order.ts","../src/rules/required.ts","../src/rules/id.ts","../src/rules/refusal.ts","../src/rules/preservation.ts","../src/validate.ts"],"sourcesContent":["/**\n * The single error type this package throws.\n *\n * Same invariant as `@pptx-studio/opc` and `@pptx-studio/xml`: **every failure\n * path throws a `ValidateError` and nothing else.**\n *\n * There is a second thing worth saying here, because this package is the one\n * where the distinction matters most. A *finding* is not an error. A finding is\n * the normal output of this package - it says a rule was broken, names the part\n * and the element, and is data a caller can render, sort or ignore. An error is\n * thrown only when validation itself could not be carried out, or when a caller\n * asked for bytes and the report says they must not have them.\n *\n * Getting that split wrong is how a validator becomes something people disable.\n * If every broken rule were an exception, the only way to see the second\n * problem would be to fix the first, and a caller with a deck that breaks nine\n * rules would learn about them one export at a time.\n */\n\n/**\n * Machine-readable failure reasons.\n *\n * Deliberately few. Almost everything this package has to say is a finding.\n */\nexport const VALIDATE_ERROR_CODES = [\n /**\n * The report carries at least one fatal finding this session introduced, and\n * a caller asked for the bytes anyway.\n *\n * The one that stops a repair prompt reaching a user. `detail.report` carries\n * the whole report, so the caller does not have to re-run validation to find\n * out what was wrong.\n */\n 'ERR_VALIDATION_FAILED',\n /**\n * Validation could not be carried out at all.\n *\n * Not \"the package is invalid\" - \"the package could not be read far enough to\n * ask the questions\". A `[Content_Types].xml` that will not parse is this,\n * because without it no part has a content type and there is nothing to\n * validate against.\n */\n 'ERR_UNVALIDATABLE',\n /** A caller named a rule id that does not exist. */\n 'ERR_UNKNOWN_RULE',\n] as const;\n\nexport type ValidateErrorCode = (typeof VALIDATE_ERROR_CODES)[number];\n\nexport interface ValidateErrorDetail {\n /** The part the failure is about, if it is about one. */\n readonly part?: string;\n /** The rule id a caller got wrong, for `ERR_UNKNOWN_RULE`. */\n readonly rule?: string;\n /**\n * The full report, for `ERR_VALIDATION_FAILED`.\n *\n * Typed `unknown` rather than `Report` on purpose: `report.ts` imports this\n * module for the error, so typing this field would make the two circular.\n * Callers narrow it with `isReport`.\n */\n readonly report?: unknown;\n}\n\nexport class ValidateError extends Error {\n readonly code: ValidateErrorCode;\n readonly detail: ValidateErrorDetail;\n\n constructor(code: ValidateErrorCode, message: string, detail: ValidateErrorDetail = {}) {\n super(message);\n this.name = 'ValidateError';\n this.code = code;\n this.detail = detail;\n }\n}\n\nexport function isValidateError(value: unknown): value is ValidateError {\n return value instanceof ValidateError;\n}\n","/**\n * The twenty-nine rules, and the evidence for each.\n *\n * ## Why a table and not twenty-nine functions\n *\n * The functions are in the files beside this one. What lives here is the part a\n * person reads: what each rule claims, how sure we are, and *how we know*. A\n * validator whose rules exist only as code is a validator nobody can audit, and\n * this one has to be audited, because roughly half of it enforces things no\n * schema says.\n *\n * That is the fact that shapes the whole package. ECMA-376 is a description of\n * a file format; PowerPoint is an implementation that refuses files the\n * description permits. Sub-phase 0.7 and the corpus bisections in\n * `tools/corpus/ROSTER.md` found nineteen such refusals by building a package\n * with one change in it and watching PowerPoint decline to open it - no\n * diagnostic, no log, no part named, just \"PowerPoint could not open the file\"\n * or `0x80070570`. Every rule below whose `evidence` says `measured` came from\n * that loop and from nowhere else.\n *\n * So each rule carries three things beyond its check:\n *\n * - `evidence` - `schema` (ECMA-376 says so), `measured` (we watched PowerPoint\n * refuse it), or `both`.\n * - `why` - the sentence that justifies the rule to somebody who is about to\n * delete it because it fired on their file.\n * - `severity` - `fatal` refuses an export; `warning` is reported and does not.\n *\n * ## On being wrong in the safe direction\n *\n * A false positive here blocks an export a user wanted. A false negative hands\n * them a file PowerPoint will not open, with no way to find out why. Those are\n * not symmetric, but the first is not free either - a validator that fires on\n * good files gets turned off, and then it catches nothing.\n *\n * The resolution is `origin`, which lives on the finding rather than here: a\n * fatal a caller *introduced* refuses the export, and the identical fatal that\n * was already in the file when it was opened is reported and does not. That is\n * the same split `PartStore.write` already makes for dangling relationships,\n * and for the same reason - refusing to re-export a file we did not break makes\n * the file unopenable in this editor and does not fix anything.\n */\n\nexport type RuleCategory =\n 'package' | 'relationships' | 'order' | 'required' | 'ids' | 'refused' | 'preservation';\n\nexport type Severity = 'fatal' | 'warning';\n\n/** Where the rule comes from. See the header. */\nexport type Evidence = 'schema' | 'measured' | 'both';\n\nexport interface Rule {\n readonly id: RuleId;\n readonly category: RuleCategory;\n readonly severity: Severity;\n readonly evidence: Evidence;\n /** One line, imperative, in the voice of the thing that must be true. */\n readonly title: string;\n /** Why the rule exists, for whoever is about to argue with it. */\n readonly why: string;\n /**\n * True when the rule needs the package as it was opened as well as the\n * package about to be written.\n *\n * Six rules do. They are skipped rather than passed when no baseline is\n * given, and the report says so - a preservation rule that silently reports\n * nothing because it had nothing to compare against is worse than one that\n * did not run, because it looks like a pass.\n */\n readonly needsBaseline?: true;\n}\n\n/**\n * The shape each entry is checked against.\n *\n * `RULES` is `as const satisfies readonly RuleShape[]` rather than typed\n * `readonly Rule[]`, so that `RuleId` below can be the union of the twenty-nine\n * literal ids written here instead of `string`. Annotating the array would\n * widen `id`, and then a caller could ask for a rule that does not exist and be\n * told so only at run time.\n */\ninterface RuleShape {\n readonly id: string;\n readonly category: RuleCategory;\n readonly severity: Severity;\n readonly evidence: Evidence;\n readonly title: string;\n readonly why: string;\n readonly needsBaseline?: true;\n}\n\nexport const RULES = [\n // --- package ------------------------------------------------------------\n\n {\n id: 'V001',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'every part resolves to a content type',\n why:\n 'OPC has no default type. A part whose extension matches no `Default` and ' +\n 'which carries no `Override` has no type at all, and a consumer has no way ' +\n 'to know what it is holding. PowerPoint refuses such a package outright.',\n },\n {\n id: 'V002',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'the content-type map is internally consistent',\n why:\n 'Every `Override` names a part that exists; no extension is declared ' +\n '`Default` twice; no part is `Override`-ed twice. And the one Office ' +\n 'omission that is famous for it: whenever any `.fntdata` part exists there ' +\n 'must be a `<Default Extension=\"fntdata\" ContentType=\"application/x-fontdata\"/>`. ' +\n 'Leaving it out is the canonical \"PowerPoint found a problem with content\" ' +\n 'bug and it is what sub-phase 8.7 exists to get right.',\n },\n {\n id: 'V003',\n category: 'package',\n severity: 'fatal',\n evidence: 'schema',\n title: 'the archive carries no directory entries and no ZIP64 record',\n why:\n 'A directory entry is not a part - no OPC part name may end in a slash - so ' +\n 'writing one puts a thing in the package that nothing can name. ZIP64 is ' +\n 'refused for a narrower reason: PowerPoint reads it, but our writer emits ' +\n 'ZIP32 only, so a ZIP64 record in something we produced means a length ' +\n 'field went somewhere it should not have. Both are about what *we* hand ' +\n 'over; a package that arrives with either is reported and not refused.',\n },\n {\n id: 'V004',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'part names are ASCII, well formed, and free of pointless percent-escapes',\n why:\n 'The OPC grammar, plus the one thing it does not say. RFC 3986 §6.2.2.2 ' +\n 'normalisation is enforced by PowerPoint rather than merely recommended: a ' +\n 'percent-escape of an *unreserved* character is a whole-package refusal ' +\n 'with `0x808D1005`. Measured nine for nine on one-name packages - `%2D`, ' +\n '`%41`, `%5F` and `%7E` refused; `%20`, `%23`, `%24`, `%2C` and `%3A` open. ' +\n '`@pptx-studio/opc` reports this as a warning (`M1.8`) because it must open ' +\n 'what it is given; here it is fatal, because we are about to write it.',\n },\n {\n id: 'V005',\n category: 'package',\n severity: 'fatal',\n evidence: 'both',\n title: 'there is exactly one main presentation part, of a matching content type',\n why:\n '`_rels/.rels` must carry exactly one `officeDocument` relationship and it ' +\n 'must resolve to a part whose content type is one of the four PresentationML ' +\n 'main-part types. And the pairing PowerPoint enforces outside the schema: it ' +\n 'checks the *file extension* against that content type and refuses the pair ' +\n 'when they disagree, which is why a macro-enabled deck has to be written ' +\n '`.pptm`. `a32-macros` is the corpus deck that measured it.',\n },\n\n // --- relationships ------------------------------------------------------\n\n {\n id: 'V006',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'both',\n title: 'every relationship reference resolves in its own part’s `.rels`',\n why:\n '`r:id`, `r:embed`, `r:link`, `r:pict`, `r:dm`, `r:lo`, `r:qs`, `r:cs` and ' +\n 'every other attribute in the relationship namespace. Relationship ids are ' +\n '`xsd:ID` scoped to one `.rels` part, so the lookup is always against the ' +\n 'referring part’s own collection and never against a global registry - a ' +\n 'global one is not a shortcut, it is a bug. A dangling reference is fatal ' +\n 'where an orphan relationship is harmless, which is the asymmetry that ' +\n 'decides which direction media garbage collection may be aggressive in.',\n },\n {\n id: 'V007',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'schema',\n title: 'relationship ids are unique within a `.rels` and match the `xsd:ID` grammar',\n why:\n '`Relationship/@Id` is `xsd:ID`: an XML Name, unique in its document. Two ' +\n 'relationships sharing an id in one `.rels` makes every reference to it ' +\n 'ambiguous, and which one a consumer picks is not defined anywhere.',\n },\n {\n id: 'V008',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'both',\n title: 'internal targets resolve inside the package, relative to the source part’s folder',\n why:\n 'A target is resolved against the folder of the part that *owns the `.rels`*, ' +\n 'not against the package root and not against the `.rels` part’s own folder. ' +\n 'Getting that wrong moves every relative target one directory up and is the ' +\n 'classic reason a rebuilt deck loses all its images at once. `TargetMode=' +\n '\"External\"` is passed through untouched and not resolved at all.',\n },\n {\n id: 'V009',\n category: 'relationships',\n severity: 'fatal',\n evidence: 'measured',\n title: 'the relationship edges a part must have, and the ones it must not',\n why:\n 'Four findings, none of them in any schema, all found by bisection. ' +\n '(1) A slide needs **exactly one** `slideLayout` relationship resolving to a ' +\n 'layout part - zero, two, one pointing at a master and one pointing at a ' +\n 'missing part were each built as a single change and each refused; the ' +\n 'binding lives only in the rels part, which is why \"change layout\" is a ' +\n 'relationship rewrite. (2) A layout needs exactly one `slideMaster`. ' +\n '(3) A `cx:chartSpace` part with no `.rels` of its own is a whole-package ' +\n 'refusal - it needs a `chartStyle` and a `chartColorStyle`, where the classic ' +\n '`c:chartSpace` needs neither. (4) A media part may not be both a media ' +\n 'object’s target and a transition’s `p:snd`; two copies of the same bytes ' +\n 'open, one shared copy does not.',\n },\n\n // --- element order ------------------------------------------------------\n\n {\n id: 'V010',\n category: 'order',\n severity: 'fatal',\n evidence: 'both',\n title: 'children appear in schema-sequence order',\n why:\n 'OOXML complex types are `xsd:sequence` almost everywhere, and PowerPoint ' +\n 'enforces it. Microsoft’s own Open XML SDK shipped a regression that merely ' +\n 'swapped two elements in `slideMaster1.xml` and PowerPoint refused the file. ' +\n 'The ranks come from `@pptx-studio/xml`’s table, generated from the ECMA-376 ' +\n 'Transitional schemas and checked against 194 148 elements PowerPoint wrote. ' +\n 'This rule also covers the two the plan calls out by name, because the table ' +\n 'already ranks them: `a:rPr` before `a:t`, and `a:endParaRPr` last in `a:p`.',\n },\n {\n id: 'V011',\n category: 'order',\n severity: 'fatal',\n evidence: 'schema',\n title: '`extLst` is last among its siblings, and every `a:ext` carries a `@uri`',\n why:\n 'Its own rule rather than a case of `V010`, because it has to hold in the ' +\n 'places the generated table cannot rank - extension markup, `xsd:any` ' +\n 'wildcards, and the vocabularies outside the four schemas we generate from. ' +\n '`extLst` is always last in every type that has one, and an `a:ext` without ' +\n 'a `@uri` is an extension nobody can identify, which makes it unpreservable: ' +\n 'the whole `extLst` contract is \"carry it through untouched, keyed by uri\".',\n },\n {\n id: 'V012',\n category: 'order',\n severity: 'fatal',\n evidence: 'both',\n title: 'no child appears in a parent whose content model has no place for it',\n why:\n 'Ordering catches a child in the wrong *position*; this catches one in the ' +\n 'wrong *parent*, which the ordering rule cannot see because an unrankable ' +\n 'child is skipped there rather than reported. The case that made it a rule ' +\n 'is measured: `a:ahXY` or `a:cxn` as a direct child of `a:custGeom`, without ' +\n 'its `a:ahLst`/`a:cxnLst` wrapper, is a whole-package refusal. Only parents ' +\n 'the table knows and whose model has no `xsd:any` are checked, and markup in ' +\n 'a namespace the table does not cover is left alone.',\n },\n\n // --- required -----------------------------------------------------------\n\n {\n id: 'V013',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:presentation` carries `p:notesSz`',\n why:\n 'The asymmetry that catches people: in `CT_Presentation`, `p:sldSz` is ' +\n '`[0..1]` and `p:notesSz` is `[1..1]`. A generator that treats the two the ' +\n 'same way, or that omits both because the deck has no notes, writes a ' +\n 'presentation part that is missing a required child.',\n },\n {\n id: 'V014',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:clrMap` carries all twelve attributes',\n why:\n '`CT_ColorMapping` has twelve attributes - `bg1`, `tx1`, `bg2`, `tx2`, ' +\n '`accent1`…`accent6`, `hlink`, `folHlink` - and every one is required. There ' +\n 'is no default and no partial map: eleven of twelve is not a map with one ' +\n 'slot missing, it is an invalid element. This is also the element that ' +\n 'decides what `bg1` and `tx1` resolve to, so a wrong one is a deck that ' +\n 'renders in the wrong colours everywhere at once.',\n },\n {\n id: 'V015',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:spTree` begins with `p:nvGrpSpPr` then `p:grpSpPr`',\n why:\n 'A shape tree is a group shape, and `CT_GroupShape` requires both of them ' +\n 'first, in that order, before any child shape. An empty slide still has ' +\n 'them. This is separate from `V010` because the failure is a missing ' +\n 'required child rather than a misordered optional one, and the two need ' +\n 'different messages: \"add this\" against \"move this\".',\n },\n {\n id: 'V016',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: 'every text body has `a:bodyPr` and at least one `a:p`',\n why:\n '`CT_TextBody` is `bodyPr` then optional `lstStyle` then `a:p` at ' +\n '`[1..unbounded]`. A shape whose text was deleted down to nothing is the ' +\n 'way this gets broken in an editor: the last paragraph goes, and what is ' +\n 'left is a `p:txBody` with no `a:p` in it. An empty paragraph is not the ' +\n 'same as no paragraph, and `a:endParaRPr` is where its height comes from.',\n },\n {\n id: 'V017',\n category: 'required',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:graphicFrame` carries `p:xfrm` and `a:graphic`',\n why:\n 'And note the namespace: it is `p:xfrm`, PresentationML, not the `a:xfrm` ' +\n 'that every other shape uses. A graphic frame has no placeholder-inherited ' +\n 'geometry path, so this is also the reason sub-phase 7.4 gives a rebound ' +\n 'chart or table a *copy* of the target layout’s transform instead of ' +\n 'deleting its own the way it does for every other shape - delete it there ' +\n 'and the frame collapses to zero size.',\n },\n\n // --- ids ----------------------------------------------------------------\n\n {\n id: 'V018',\n category: 'ids',\n severity: 'fatal',\n evidence: 'schema',\n title: '`p:sldId/@id` is 256…2147483647 and unique',\n why:\n '`ST_SlideId` is not zero-based and not unbounded. The floor of 256 is the ' +\n 'part people get wrong, because nothing about a first slide suggests its id ' +\n 'should start there. Four id spaces exist in a presentation and they are not ' +\n 'one allocator; this is the first of them.',\n },\n {\n id: 'V019',\n category: 'ids',\n severity: 'fatal',\n evidence: 'both',\n title: 'master and layout ids are ≥ 2147483648 and unique **across both lists**',\n why:\n '`ST_SlideMasterId` and `ST_SlideLayoutId` are both \"2147483648 and up\" and ' +\n 'no schema says they may not overlap. PowerPoint allocates them from one ' +\n 'running counter - master, its layouts, next master, its layouts - and ' +\n 'refuses a package that does not. Found by bisection when `a12-masters` ' +\n 'would not open: two counters are indistinguishable from correct with one ' +\n 'master and collide on the second, so **every** two-master package was ' +\n 'refused.',\n },\n {\n id: 'V020',\n category: 'ids',\n severity: 'fatal',\n evidence: 'both',\n title: '`p:cNvPr/@id` is unique within its part and ≤ 2147483647',\n why:\n 'Unique *within a part*, and free to repeat across parts - a shape id is not ' +\n 'a document-wide identity and treating it as one is how a duplicate-slide ' +\n 'implementation ends up renumbering things it should not. The range is ' +\n 'measured rather than read: `ST_DrawingElementId` is `xsd:unsignedInt`, but ' +\n 'every value from 0 to 2147483647 opens, 2147483648…4294967294 are ' +\n 'whole-package refusals, and 4294967295 opens - PowerPoint reads the ' +\n 'attribute as a signed 32-bit integer and keeps `0xFFFFFFFF` as a sentinel ' +\n 'it renumbers away on save. `a39-large-ids` is the corpus deck.',\n },\n {\n id: 'V021',\n category: 'ids',\n severity: 'warning',\n evidence: 'schema',\n title: 'a slide placeholder’s `(type, idx)` has a counterpart in its layout',\n why:\n 'A `p:ph` that matches nothing in the layout inherits nothing: no geometry, ' +\n 'no text style, no prompt. PowerPoint opens the file and draws the shape at ' +\n 'whatever it can work out, which is why this is a warning and not fatal - ' +\n 'the deck is not refused, it is silently wrong. Matching follows the five ' +\n 'tiers sub-phase 7.1 hardens, and the asymmetry that matters is checked ' +\n 'here too: slide→layout matches on `(type, idx)` where layout→master ' +\n 'matches on **type only**.',\n },\n\n // --- refused ------------------------------------------------------------\n\n {\n id: 'V022',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: '`p:ph/@type` is not `hdr` or `sldImg` outside a notes or handout part',\n why:\n 'A whole-package refusal, on a slide layout and on a slide alike, either one ' +\n 'alone with no other change. The other seven content types were built as ' +\n 'one-type packages in the same bisection and every one opens: `obj`, ' +\n '`chart`, `tbl`, `clipArt`, `dgm`, `media`, `pic`. Nothing in the schema ' +\n 'says so - `CT_Placeholder` is one complex type shared by masters, layouts, ' +\n 'slides, notes slides and handout masters, and `ST_PlaceholderType` is one ' +\n 'enumeration holding all sixteen values. The restriction is real and ' +\n 'unwritten: those two belong to the notes and handout families.',\n },\n {\n id: 'V023',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: 'every geometry guide named is a guide that is defined',\n why:\n 'A whole-package refusal, not a repair and not a dropped shape. It applies ' +\n 'both to an `a:gd` formula naming an adjust value no `a:avLst` defines and ' +\n 'to an `a:pt` coordinate naming a guide no `a:gdLst` defines. ' +\n '`ST_GeomGuideName` is an unconstrained token, so this is schema-legal ' +\n 'markup refused for a reason no schema states - and it is the rule that ' +\n 'sub-phase 2.5 needs, because dragging an adjust handle is exactly the ' +\n 'operation that can write a formula referring to a guide that is no longer ' +\n 'there.',\n },\n {\n id: 'V024',\n category: 'refused',\n severity: 'fatal',\n evidence: 'both',\n title: '`c:tx` holds `c:strRef` or `c:v`, never `c:strLit`',\n why:\n '`CT_SerTx` is a choice of exactly those two. The trap is that `c:cat` and ' +\n '`c:val`, two elements away in the same series, both accept the literal ' +\n 'forms - so the markup looks like something that ought to work, and it is a ' +\n 'whole-package refusal.',\n },\n {\n id: 'V025',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: 'no `p:control`',\n why:\n 'A whole-package refusal in all eight forms tried: bare, name-only, with and ' +\n 'without `r:id`, with a `p:pic` preview, with an ActiveX part and its `.bin`, ' +\n 'and inside a macro-enabled package. An empty `p:controls` is accepted, ' +\n 'which places the refusal precisely on the child element. We do not author ' +\n 'ActiveX controls and never will; the rule exists so that a file that has ' +\n 'one is not handed back with it re-serialised into a form PowerPoint likes ' +\n 'less than the original.',\n },\n {\n id: 'V026',\n category: 'refused',\n severity: 'fatal',\n evidence: 'measured',\n title: 'a `cs:chartStyle` carries all thirty-one of its entries',\n why:\n 'Four entries refused; thirty-one opened. And the shape of the finding is ' +\n 'the interesting half: a chart with **no** chart-style relationship at all is ' +\n 'fine, so this is not \"the part is required\" - it is \"if the part exists it ' +\n 'must be complete\". A subset is worse than an absence, which is the opposite ' +\n 'of what a partial-styling model would predict.',\n },\n\n // --- preservation -------------------------------------------------------\n\n {\n id: 'V027',\n category: 'preservation',\n severity: 'fatal',\n evidence: 'schema',\n needsBaseline: true,\n title: 'a part nobody edited comes back out byte-for-byte',\n why:\n 'The load-bearing one, and the reason the architecture is what it is. ' +\n 'Preserving charts, SmartArt, animations, OLE and macros is unachievable in ' +\n 'any design where the writer has to *understand* a feature to emit it, so ' +\n 'preservation is the default state rather than a feature - and this rule is ' +\n 'where that stops being an intention. `ppt/embeddings/*.bin` is called out ' +\n 'inside it: those are OLE2/CFB compound files and any rewrite of one is a ' +\n 'guaranteed repair prompt.',\n },\n {\n id: 'V028',\n category: 'preservation',\n severity: 'fatal',\n evidence: 'schema',\n needsBaseline: true,\n title: 'no `mc:AlternateContent` branch and no `extLst` was rebuilt',\n why:\n 'Two things we hold opaque, for one reason: we do not know what is in them. ' +\n 'An `mc:AlternateContent` branch we do not understand must arrive and leave ' +\n 'identical, because `mc:Choice/@Requires` names a *prefix* and rewriting the ' +\n 'branch is how ignorable extension markup becomes a hard error. An `extLst` ' +\n 'is an ordered list keyed by `@uri` and never a typed model that is rebuilt ' +\n 'from fields - `a34-extlst` measured that PowerPoint carries an unknown ' +\n '`a:ext/@uri` through untouched, so anything we drop there is something the ' +\n 'file would otherwise have kept forever.',\n },\n {\n id: 'V029',\n category: 'preservation',\n severity: 'fatal',\n evidence: 'both',\n needsBaseline: true,\n title: 'text and field identity survive: `xml:space`, `a:fld/@id`, cached field text',\n why:\n 'Three small things that are each silently destructive. An `a:t` with ' +\n 'leading or trailing whitespace needs `xml:space=\"preserve\"` if it was ' +\n 'written with it, because dropping the attribute changes what the text *is*. ' +\n '`a:fld/@id` is a required `ST_Guid` and regenerating one can make PowerPoint ' +\n 'repair the file. And a field’s cached `a:t` is the only thing that renders ' +\n 'when we cannot evaluate the field ourselves, so discarding it turns a date ' +\n 'placeholder into an empty box on every consumer that is not PowerPoint.',\n },\n] as const satisfies readonly RuleShape[];\n\nexport type RuleId = (typeof RULES)[number]['id'];\n\nconst BY_ID = new Map<string, Rule>(RULES.map((rule) => [rule.id, rule as Rule]));\n\nexport function ruleById(id: string): Rule | undefined {\n return BY_ID.get(id);\n}\n\nexport const RULE_IDS: readonly RuleId[] = RULES.map((rule) => rule.id);\n\n/** Rules that need the package as it was opened. See `Rule.needsBaseline`. */\nexport const BASELINE_RULES: readonly RuleId[] = RULES.filter(\n (rule) => 'needsBaseline' in rule,\n).map((rule) => rule.id);\n","import type { Location } from './location.js';\nimport { ruleById, type RuleCategory, type RuleId, type Severity } from '../rules/rules.js';\n\n/**\n * What validation produces.\n *\n * ## Origin, and why it is computed rather than guessed\n *\n * The hardest question this package has to answer is not \"is this file valid\".\n * It is **\"did we break it\"**, and those are different questions with different\n * consequences. A fatal finding in a deck the user imported ten seconds ago is\n * information; the same finding in a deck they just edited is a bug in us, and\n * handing over the bytes would give them a repair prompt with no explanation.\n *\n * Refusing both would be the strict-looking choice and it is the wrong one. It\n * would mean that a deck with one pre-existing defect - a dangling image\n * relationship, say, which PowerPoint tolerates and which is common in files\n * that have been through three other tools - could be opened in this editor and\n * never saved again. The editor would be refusing to give the user back their\n * own file over a problem it did not cause and cannot fix. `PartStore.write`\n * already made exactly this call for dangling relationships, and this is the\n * same call generalised to all twenty-nine rules.\n *\n * So `origin` is not a per-rule judgement call. It is computed by running the\n * rules a second time against the package **as it was opened** and differencing\n * the two reports: a finding that is in both is `inherited`, one that is only in\n * the new report is `introduced`. That is exact, it needs no rule to reason\n * about history, and it cannot drift from what the rules actually do.\n *\n * The second pass only happens when the first found something fatal, so a clean\n * export - the overwhelmingly common case - pays nothing for it.\n */\n\nexport type Origin =\n /** The finding is in the package we are about to write and was not in the original. */\n | 'introduced'\n /** The finding was already there when the package was opened. */\n | 'inherited'\n /** No baseline was supplied, so the question was not asked. */\n | 'unknown';\n\nexport interface Finding {\n readonly rule: RuleId;\n readonly severity: Severity;\n readonly category: RuleCategory;\n readonly where: Location;\n /**\n * What is wrong, in one sentence, naming the values involved.\n *\n * Written to be read on its own: a message that says \"invalid id\" and leaves\n * the reader to go and look is a message that costs more than it saves.\n */\n readonly message: string;\n readonly origin: Origin;\n}\n\n/** A rule that did not run, and why. Never silent - see `Report.skipped`. */\nexport interface SkippedRule {\n readonly rule: RuleId;\n readonly why: string;\n}\n\n/** Something that could not be read. Not a rule violation; a gap in coverage. */\nexport interface ReadProblem {\n readonly part: string;\n readonly message: string;\n}\n\nexport interface Report {\n /** Sorted: fatal before warning, then by part, then by offset. */\n readonly findings: readonly Finding[];\n /** Rules that ran. */\n readonly checked: readonly RuleId[];\n /**\n * Rules that did not run, and why.\n *\n * Present so that a report can never quietly mean less than it looks like it\n * means. Six rules need the package as it was opened; asked to validate a\n * package with no baseline they report nothing, and \"reported nothing\" and\n * \"found nothing\" are the same shape on a screen and opposite in meaning.\n */\n readonly skipped: readonly SkippedRule[];\n /** Parts that could not be read, and the rules that therefore did not see them. */\n readonly problems: readonly ReadProblem[];\n /** Fatal findings this session introduced. The number that refuses an export. */\n readonly blocking: number;\n /** True when nothing blocking was found. Not the same as \"no findings\". */\n readonly ok: boolean;\n}\n\n/** Fatal, then warning; then by part; then by offset; then by rule. */\nfunction compareFindings(a: Finding, b: Finding): number {\n if (a.severity !== b.severity) return a.severity === 'fatal' ? -1 : 1;\n if (a.where.part !== b.where.part) return a.where.part.localeCompare(b.where.part);\n const offsetA = a.where.offset ?? -1;\n const offsetB = b.where.offset ?? -1;\n if (offsetA !== offsetB) return offsetA - offsetB;\n return a.rule.localeCompare(b.rule);\n}\n\n/**\n * The key two reports are differenced on.\n *\n * Includes the message, because the message carries the instance - the id that\n * collided, the guide that was not defined. Two findings of the same rule at\n * the same place with different values are different findings, and treating\n * them as one would let an introduced defect hide behind an inherited one.\n */\nexport function findingKey(finding: Finding): string {\n return [finding.rule, finding.where.part, finding.where.xpath ?? '', finding.message].join(\n '\\u0000',\n );\n}\n\nexport function buildReport(input: {\n readonly findings: readonly Finding[];\n readonly checked: readonly RuleId[];\n readonly skipped: readonly SkippedRule[];\n readonly problems: readonly ReadProblem[];\n}): Report {\n const findings = [...input.findings].sort(compareFindings);\n const blocking = findings.filter(\n (finding) => finding.severity === 'fatal' && finding.origin !== 'inherited',\n ).length;\n return {\n findings,\n checked: input.checked,\n skipped: input.skipped,\n problems: input.problems,\n blocking,\n ok: blocking === 0,\n };\n}\n\nexport function isReport(value: unknown): value is Report {\n return (\n typeof value === 'object' &&\n value !== null &&\n Array.isArray((value as Report).findings) &&\n typeof (value as Report).blocking === 'number'\n );\n}\n\nexport interface FormatOptions {\n /** Include `inherited` findings. Default true. */\n readonly inherited?: boolean;\n /** Include warnings. Default true. */\n readonly warnings?: boolean;\n /** Append each rule's `why`, once per rule. Default false. */\n readonly explain?: boolean;\n}\n\n/**\n * A report as text.\n *\n * Grouped by part rather than by rule, because the question a reader has is\n * \"what is wrong with this file\", and a file is a set of parts. Grouping by\n * rule is the right shape for the corpus gate and the wrong one here.\n */\nexport function formatReport(report: Report, options: FormatOptions = {}): string {\n const showInherited = options.inherited ?? true;\n const showWarnings = options.warnings ?? true;\n\n const shown = report.findings.filter(\n (finding) =>\n (showInherited || finding.origin !== 'inherited') &&\n (showWarnings || finding.severity === 'fatal'),\n );\n\n const lines: string[] = [];\n if (shown.length === 0) {\n // 'nothing was found' and 'nothing survived the filter' are different\n // sentences, and a reader who asked to hide inherited findings has to be\n // able to tell which one they are looking at.\n lines.push(report.findings.length === 0 ? 'no findings' : 'no findings shown');\n } else {\n const byPart = new Map<string, Finding[]>();\n for (const finding of shown) {\n const bucket = byPart.get(finding.where.part);\n if (bucket) bucket.push(finding);\n else byPart.set(finding.where.part, [finding]);\n }\n for (const [part, findings] of byPart) {\n lines.push('');\n lines.push(' ' + (part === '/' ? '(package)' : part));\n for (const finding of findings) {\n const tag =\n finding.severity === 'fatal'\n ? finding.origin === 'inherited'\n ? 'fatal (already there)'\n : 'fatal'\n : 'warning';\n lines.push(' ' + finding.rule + ' ' + tag);\n if (finding.where.xpath !== null) lines.push(' ' + finding.where.xpath);\n lines.push(' ' + finding.message);\n }\n }\n }\n\n for (const problem of report.problems) {\n lines.push('');\n lines.push(' ' + problem.part + ' could not be read: ' + problem.message);\n }\n for (const skipped of report.skipped) {\n lines.push('');\n lines.push(' ' + skipped.rule + ' did not run: ' + skipped.why);\n }\n\n if (options.explain === true) {\n const seen = new Set<RuleId>();\n for (const finding of shown) {\n if (seen.has(finding.rule)) continue;\n seen.add(finding.rule);\n const rule = ruleById(finding.rule);\n if (rule === undefined) continue;\n lines.push('');\n lines.push(' ' + rule.id + ' - ' + rule.title);\n lines.push(' ' + rule.why);\n }\n }\n\n lines.push('');\n lines.push(\n 'validate: ' +\n String(report.checked.length) +\n ' rule(s), ' +\n String(report.findings.length) +\n ' finding(s), ' +\n String(report.blocking) +\n ' blocking',\n );\n return lines.join('\\n');\n}\n","import {\n attribute,\n type XAttribute,\n type XDocument,\n type XElement,\n type XNode,\n} from '@pptx-studio/xml';\n\n/**\n * Where a finding is, in a form a person can act on.\n *\n * ## Why an XPath and not a byte offset\n *\n * Both, actually - the offset is on the finding too, because it is what\n * `cli bisect` needs in sub-phase 1.5 and what a diff viewer can highlight. But\n * the offset is useless to a human: it names a position in a file that is\n * usually one line long and often two megabytes wide, and it stops being true\n * the moment anything above it changes.\n *\n * An XPath survives editing, survives reformatting, and can be pasted into\n * every XML tool there is. More to the point, it is the only form in which\n * a report about eleven parts is *readable* - `ppt/slides/slide3.xml` at\n * `/p:sld/p:cSld/p:spTree/p:sp[2]/p:nvSpPr/p:cNvPr/@id` says what is wrong in\n * one line, and byte 41 207 does not.\n *\n * ## Prefixes are the document's own, always\n *\n * The path is built from `qname` as written in the file - not from a canonical\n * prefix table, and not from the namespace URI. If a part spells the\n * PresentationML namespace `pp:` instead of `p:`, the path says `pp:`, because\n * the point of the path is that a reader can find the element in the file in\n * front of them. A canonicalised path would be *more correct* as an XPath\n * expression and less useful as a location, and this is a diagnostic rather\n * than a query.\n *\n * The same choice is made everywhere in this project for the same reason, and\n * it is not stylistic: `mc:Ignorable` and `mc:Choice/@Requires` hold prefixes\n * rather than URIs, so a prefix is load-bearing data in OOXML and inventing one\n * is never a neutral act.\n *\n * ## The positional predicate\n *\n * `[n]` is emitted only where it disambiguates - that is, when the element has\n * a sibling of the same `qname`. `/p:sld/p:cSld/p:spTree/p:sp[2]` is exact;\n * `/p:sld[1]/p:cSld[1]/p:spTree[1]` is noise. Positions are 1-based, counting\n * only elements of that name, which is what XPath means by `position()` inside\n * a name test and is what every XML tool will agree with.\n */\n\n/** A location inside a part, or the part itself. */\nexport interface Location {\n /**\n * The part name, with its leading slash: `/ppt/slides/slide1.xml`.\n *\n * `/` means the finding is about the package rather than about any one part -\n * the archive shape, the content-type map, the relationship graph as a whole.\n */\n readonly part: string;\n /** The path to the element or attribute, or `null` for a whole-part finding. */\n readonly xpath: string | null;\n /** Byte offset of the node in the part's source, or `null`. For `cli bisect`. */\n readonly offset: number | null;\n}\n\n/** A location that names a part and nothing inside it. */\nexport function partLocation(part: string): Location {\n return { part, xpath: null, offset: null };\n}\n\n/** The location of the package itself: the archive, the content types, the graph. */\nexport const PACKAGE_LOCATION: Location = { part: '/', xpath: null, offset: null };\n\n/** 1-based position among same-named element siblings, or `null` if it is alone. */\nfunction positionAmongSiblings(element: XElement): number | null {\n const parent = element.parent;\n if (parent === undefined) return null;\n let position = 0;\n let seen = 0;\n for (const child of parent.children) {\n if (child.type !== 'element' || child.qname !== element.qname) continue;\n seen++;\n if (child === element) position = seen;\n }\n return seen > 1 ? position : null;\n}\n\n/**\n * The XPath of an element, from the document root.\n *\n * Never throws and never returns an empty string: a detached element - one\n * whose `parent` chain does not reach a root - still gets its own name, so a\n * finding built from a node the caller synthesised is degraded rather than\n * lost.\n */\nexport function xpathOf(element: XElement): string {\n const steps: string[] = [];\n for (let node: XElement | undefined = element; node !== undefined; node = node.parent) {\n const position = positionAmongSiblings(node);\n steps.push(position === null ? node.qname : node.qname + '[' + String(position) + ']');\n }\n steps.reverse();\n return '/' + steps.join('/');\n}\n\n/** The XPath of an attribute: its owner's path, then `/@qname`. */\nexport function xpathOfAttribute(owner: XElement, attr: XAttribute | string): string {\n const qname = typeof attr === 'string' ? attr : attr.qname;\n return xpathOf(owner) + '/@' + qname;\n}\n\n/** A location for an element inside a named part. */\nexport function elementLocation(part: string, element: XElement): Location {\n return { part, xpath: xpathOf(element), offset: element.start };\n}\n\n/**\n * A location for one attribute of an element.\n *\n * The offset is the attribute's own start when the element carries it, and the\n * element's start when it does not - which is the case that matters, because a\n * *missing* required attribute is a finding and it has to point somewhere.\n */\nexport function attributeLocation(part: string, element: XElement, qname: string): Location {\n const attr = attribute(element, qname);\n return {\n part,\n xpath: xpathOfAttribute(element, qname),\n offset: attr === undefined ? element.start : attr.start,\n };\n}\n\n/**\n * `line:column` for an offset, 1-based, or `null`.\n *\n * Not part of `Location`, because computing it means scanning the source from\n * the beginning and a report with three hundred findings would scan it three\n * hundred times. Callers that render a report for a human ask for it once, at\n * the point of rendering, for the findings they are about to show.\n */\nexport function lineColumn(source: string, offset: number): { line: number; column: number } {\n let line = 1;\n let lineStart = 0;\n const limit = Math.min(offset, source.length);\n for (let i = 0; i < limit; i++) {\n if (source.charCodeAt(i) === 0x0a) {\n line++;\n lineStart = i + 1;\n }\n }\n return { line, column: limit - lineStart + 1 };\n}\n\n/** Document order, for sorting findings within a part. */\nexport function inDocumentOrder(a: XNode, b: XNode): number {\n return a.start - b.start;\n}\n\n/** The root element's qname, for the handful of rules that dispatch on it. */\nexport function rootName(document: XDocument): string {\n return document.root.qname;\n}\n","import {\n CONTENT_TYPES_PART,\n isContentTypesStreamName,\n isRelationshipPartName,\n normalizePartName,\n type PartStore,\n type PartName,\n type ZipArchive,\n} from '@pptx-studio/opc';\nimport { parseXml, type XDocument } from '@pptx-studio/xml';\nimport type { Location } from './report/location.js';\nimport type { Finding, ReadProblem } from './report/report.js';\nimport { ruleById, type RuleId } from './rules/rules.js';\n\n/**\n * The state a rule reads, and the one method it writes.\n *\n * Every rule is `(ctx: Context) => void`. That is a deliberately small\n * interface, and it is the same shape `checkLayering({manifests, catalog})` and\n * `checkCorpus({manifests, files, ...})` already have in this repository, for\n * the same reason: a rule that takes a context and returns nothing is a rule\n * that can be run against a package assembled in a test, with no temporary\n * directory, no archive on disk and no other twenty-eight rules running beside\n * it obscuring which one fired.\n *\n * ## Everything is lazy, and everything is cached\n *\n * Twelve of the rules want the parsed tree of every XML part. Parsing each part\n * once per rule would be twelve passes over a deck that can be two hundred\n * megabytes. Parsing all of them up front would be one pass too many for the\n * package-level rules, which need no trees at all.\n *\n * So `document()` parses on first ask and remembers. A part that is not XML\n * returns `null` and is not asked again. A part that will not *parse* also\n * returns `null` - and records a `ReadProblem`, because a rule that silently\n * saw nothing is indistinguishable from a rule that found nothing, and those\n * are opposite answers.\n */\nexport interface Context {\n /** The package about to be handed over, or the one being inspected. */\n readonly store: PartStore;\n /** The archive bytes, when the caller had them. `null` when only a store was given. */\n readonly bytes: Uint8Array | null;\n /**\n * The archive those bytes describe, central directory only - nothing is\n * inflated to build it.\n *\n * `PartStore` deliberately does not expose this. It drops directory entries\n * on the way in, because a directory entry is not a part and carrying a thing\n * with no part name through the whole system would mean every consumer has to\n * remember it is there. That is right for the store and it leaves three rules\n * with nothing to look at: whether the archive has directory entries, whether\n * it carries a ZIP64 record, and what `[Content_Types].xml` actually *says* as\n * opposed to what parsing it produced.\n *\n * `null` when the caller passed a store and no bytes; the rules that need it\n * are then skipped with a reason rather than passing vacuously.\n */\n readonly archive: ZipArchive | null;\n /** The package as it was opened. `null` for an inspection with no history. */\n readonly baseline: PartStore | null;\n\n /** Part names in package order, `[Content_Types].xml` excluded - it is not a part. */\n parts(): readonly PartName[];\n /** A part's bytes, or `null` if it is not there. Never throws. */\n read(part: string): Uint8Array | null;\n /** Content type, or `undefined` when nothing in the map covers the part. */\n contentType(part: string): string | undefined;\n /** The parsed tree, cached. `null` for binary parts and for parts that will not parse. */\n document(part: string): XDocument | null;\n /**\n * `[Content_Types].xml` as the archive holds it, parsed.\n *\n * Not reachable through `parts()`: the content-type stream is not a part. It\n * has no content type of its own and nothing ever relates to it, which is why\n * `PartStore` keeps it outside the part map entirely.\n *\n * Read from the markup rather than from `store.contentTypes` for the reason\n * `rels.ts` gives at length: `ContentTypes.parse` collapses a duplicate\n * `Default` that agrees with itself and refuses one that does not, so a rule\n * that asks the parsed map whether there are duplicates is asking the one\n * object in the system that cannot answer.\n */\n contentTypesDocument(): XDocument | null;\n\n /** The same three, against the baseline. `null` throughout when there is none. */\n baselineRead(part: string): Uint8Array | null;\n baselineDocument(part: string): XDocument | null;\n\n /**\n * True when this session replaced or added the part.\n *\n * Derived from `PartInfo.fromArchive`, which is the store's own record of\n * whether a part's bytes still come from the archive it was opened from. It\n * is the only honest source for \"did we touch this\" - a byte comparison\n * cannot tell an edit that happened to produce identical bytes from no edit\n * at all, and the preservation rules care about the difference.\n */\n edited(part: string): boolean;\n\n add(rule: RuleId, where: Location, message: string): void;\n problem(part: string, message: string): void;\n}\n\nexport interface ContextInput {\n readonly store: PartStore;\n readonly bytes?: Uint8Array | null;\n readonly archive?: ZipArchive | null;\n readonly baseline?: PartStore | null;\n}\n\n/** Content types whose parts are XML, beyond everything ending in `+xml`. */\nconst XML_CONTENT_TYPES = new Set(['application/xml', 'text/xml']);\n\nfunction isXmlContentType(contentType: string | undefined): boolean {\n if (contentType === undefined) return false;\n const base = contentType.split(';')[0]!.trim().toLowerCase();\n return base.endsWith('+xml') || XML_CONTENT_TYPES.has(base);\n}\n\nclass RuntimeContext implements Context {\n readonly store: PartStore;\n readonly bytes: Uint8Array | null;\n readonly archive: ZipArchive | null;\n readonly baseline: PartStore | null;\n\n readonly findings: Finding[] = [];\n readonly problems: ReadProblem[] = [];\n\n #parts: PartName[] | null = null;\n readonly #documents = new Map<string, XDocument | null>();\n readonly #baselineDocuments = new Map<string, XDocument | null>();\n\n constructor(input: ContextInput) {\n this.store = input.store;\n this.bytes = input.bytes ?? null;\n this.archive = input.archive ?? null;\n this.baseline = input.baseline ?? null;\n }\n\n parts(): readonly PartName[] {\n this.#parts ??= this.store.partNames;\n return this.#parts;\n }\n\n read(part: string): Uint8Array | null {\n if (!this.store.has(part)) return null;\n try {\n return this.store.read(part);\n } catch (error) {\n this.problem(part, describe(error));\n return null;\n }\n }\n\n contentType(part: string): string | undefined {\n return this.store.contentTypeOf(part);\n }\n\n document(part: string): XDocument | null {\n const key = normalizePartName(part);\n const cached = this.#documents.get(key);\n if (cached !== undefined) return cached;\n const parsed = this.#parse(part, this.read(part));\n this.#documents.set(key, parsed);\n return parsed;\n }\n\n baselineDocument(part: string): XDocument | null {\n if (this.baseline === null) return null;\n const key = normalizePartName(part);\n const cached = this.#baselineDocuments.get(key);\n if (cached !== undefined) return cached;\n const parsed = this.#parse(part, this.baselineRead(part), true);\n this.#baselineDocuments.set(key, parsed);\n return parsed;\n }\n\n #parse(part: string, bytes: Uint8Array | null, quiet = false): XDocument | null {\n if (bytes === null) return null;\n // The content type decides, not the extension. A `.bin` OLE object and a\n // `.png` are both binary and neither would tokenize; more to the point, an\n // `.xml` extension covers a `Default` that some producer typed\n // `application/octet-stream`, and parsing that would be us disagreeing with\n // the package about what it holds.\n if (!isRelationshipPartName(part) && !isXmlContentType(this.contentType(part))) return null;\n try {\n return parseXml(bytes);\n } catch (error) {\n // Not a rule violation. `@pptx-studio/xml` refuses a DOCTYPE, a bad\n // encoding and markup that is not well formed, and each of those is a\n // fact about the file rather than about one of the twenty-nine rules.\n // Recording it as a problem keeps the report honest: the rules that\n // wanted this part did not run on it.\n if (!quiet) this.problem(part, describe(error));\n return null;\n }\n }\n\n #contentTypesDocument: XDocument | null | undefined;\n\n contentTypesDocument(): XDocument | null {\n if (this.#contentTypesDocument !== undefined) return this.#contentTypesDocument;\n this.#contentTypesDocument = null;\n const archive = this.archive;\n if (archive !== null) {\n const entry = archive.entries.find((e) => isContentTypesStreamName(e.name));\n if (entry !== undefined) {\n try {\n this.#contentTypesDocument = parseXml(archive.read(entry));\n } catch (error) {\n this.problem(CONTENT_TYPES_PART, describe(error));\n }\n }\n }\n return this.#contentTypesDocument;\n }\n\n baselineRead(part: string): Uint8Array | null {\n if (this.baseline === null || !this.baseline.has(part)) return null;\n try {\n return this.baseline.read(part);\n } catch {\n return null;\n }\n }\n\n edited(part: string): boolean {\n return this.store.info(part)?.fromArchive === false;\n }\n\n add(rule: RuleId, where: Location, message: string): void {\n const definition = ruleById(rule);\n if (definition === undefined) return;\n this.findings.push({\n rule,\n severity: definition.severity,\n category: definition.category,\n where,\n message,\n // Filled in by the driver, which is the only thing that knows whether a\n // baseline pass ran. A rule never decides its own finding's history.\n origin: 'unknown',\n });\n }\n\n problem(part: string, message: string): void {\n const already = this.problems.some((p) => p.part === part && p.message === message);\n if (!already) this.problems.push({ part, message });\n }\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n const code = (error as { code?: unknown }).code;\n return typeof code === 'string' ? code + ': ' + error.message : error.message;\n }\n return String(error);\n}\n\nexport function createContext(input: ContextInput): RuntimeContext {\n return new RuntimeContext(input);\n}\n\nexport type { RuntimeContext };\n","import {\n isRelationshipPartName,\n normalizePartName,\n resolveRelativeTarget,\n sourcePartNameForRels,\n} from '@pptx-studio/opc';\nimport { attributeValue, childElements, type XElement } from '@pptx-studio/xml';\nimport type { Context } from './context.js';\n\n/**\n * Relationship parts, read as XML rather than through `Relationships`.\n *\n * This is not duplication for its own sake, and the reason is worth stating\n * because the obvious code - call `store.relationships(part)` - is wrong here in\n * a way that is invisible until a rule fails to fire.\n *\n * `Relationships.parse` **refuses** a duplicate `Id`, an `Id` that is not an\n * `xsd:ID`, and an empty `Target`. It has to: it is the type the rest of the\n * codebase uses to look relationships up, and a collection with two `rId3`s\n * cannot answer the only question anyone asks it. But three of the twenty-nine\n * rules are *about* exactly those defects, and a rule that can only see files\n * its own parser already accepted can never report them. Going through that\n * parser would turn every one of those findings into \"this part could not be\n * read\", which is true and useless.\n *\n * So the rules read the markup. That also buys the thing the plan asks for: a\n * finding gets an XPath into the `.rels` part - `/Relationships/Relationship[4]`\n * - instead of a part name and an apology.\n */\n\nconst REL_NS = 'http://schemas.openxmlformats.org/package/2006/relationships';\n\nexport interface RawRelationship {\n readonly id: string;\n readonly type: string;\n readonly target: string;\n /** `Internal` unless the attribute says otherwise; the attribute is optional. */\n readonly targetMode: string;\n /** The `<Relationship>` element, for the finding's location. */\n readonly element: XElement;\n}\n\nexport interface RelsPart {\n /** The `.rels` part's own name, e.g. `/ppt/slides/_rels/slide1.xml.rels`. */\n readonly partName: string;\n /** The part it describes, e.g. `/ppt/slides/slide1.xml`. `/` for the root rels. */\n readonly source: string;\n readonly relationships: readonly RawRelationship[];\n readonly root: XElement;\n}\n\n/**\n * Every relationship part in the package, parsed.\n *\n * A `.rels` whose root is not `Relationships` in the OPC namespace is skipped\n * and recorded as a problem, because there is nothing sensible to say about it\n * rule by rule and saying it once is better than saying it four times.\n */\nconst CACHE = new WeakMap<Context, readonly RelsPart[]>();\n\nexport function readRelsParts(ctx: Context): readonly RelsPart[] {\n const cached = CACHE.get(ctx);\n if (cached !== undefined) return cached;\n const parts = scanRelsParts(ctx);\n CACHE.set(ctx, parts);\n return parts;\n}\n\n/**\n * Memoised above, because five of the twenty-nine rules want this list and each\n * would otherwise re-walk every `.rels` part in the package. The parsed trees\n * are already cached on the context; what is saved here is the element scan and\n * the allocation, which on a three-hundred-slide deck is five passes over a\n * thousand relationship parts for one answer that cannot have changed.\n *\n * Keyed by context rather than by store, so nothing survives one validation run\n * into the next.\n */\nfunction scanRelsParts(ctx: Context): readonly RelsPart[] {\n const out: RelsPart[] = [];\n for (const partName of ctx.parts()) {\n if (!isRelationshipPartName(partName)) continue;\n const document = ctx.document(partName);\n if (document === null) continue;\n\n const root = document.root;\n if (root.local !== 'Relationships') {\n ctx.problem(partName, 'root element is <' + root.qname + '>, not <Relationships>');\n continue;\n }\n\n let source: string;\n try {\n source = partName === '/_rels/.rels' ? '/' : sourcePartNameForRels(partName);\n } catch {\n ctx.problem(partName, 'is not a well-formed relationship part name');\n continue;\n }\n\n const relationships: RawRelationship[] = [];\n for (const child of childElements(root)) {\n if (child.local !== 'Relationship') continue;\n relationships.push({\n id: attributeValue(child, 'Id') ?? '',\n type: attributeValue(child, 'Type') ?? '',\n target: attributeValue(child, 'Target') ?? '',\n targetMode: attributeValue(child, 'TargetMode') ?? 'Internal',\n element: child,\n });\n }\n out.push({ partName, source, relationships, root });\n }\n return out;\n}\n\n/** The OPC relationships namespace, for the rules that check the root element. */\nexport { REL_NS };\n\nexport interface ResolvedTarget {\n /** The absolute part name the target names, or `null` when it will not resolve. */\n readonly part: string | null;\n /** Why it would not resolve. `null` when it did. */\n readonly failure: string | null;\n}\n\n/**\n * Resolve an internal target against the folder of the part that owns the\n * `.rels` - never against the package root, and never against the `.rels`\n * part's own folder.\n *\n * The distinction is the whole of rule `V008`. `_rels/` is a directory in the\n * archive but not in the resolution model: a `Target=\"../media/image1.png\"` in\n * `/ppt/slides/_rels/slide1.xml.rels` resolves against `/ppt/slides/`, giving\n * `/ppt/media/image1.png`. Resolving it against `/ppt/slides/_rels/` instead\n * yields `/ppt/slides/media/image1.png`, which is one directory too deep and is\n * why a rebuilt deck loses every image at once rather than one of them.\n */\nexport function resolveTarget(source: string, target: string): ResolvedTarget {\n try {\n return { part: resolveRelativeTarget(source, target), failure: null };\n } catch (error) {\n return { part: null, failure: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/** Relationship ids declared in a part's `.rels`, for reference checking. */\nexport function idsOf(rels: RelsPart | undefined): ReadonlySet<string> {\n const ids = new Set<string>();\n for (const rel of rels?.relationships ?? []) ids.add(rel.id);\n return ids;\n}\n\n/** `.rels` parts keyed by the **source** part they describe, normalised. */\nexport function bySource(parts: readonly RelsPart[]): ReadonlyMap<string, RelsPart> {\n const map = new Map<string, RelsPart>();\n for (const part of parts) {\n map.set(part.source === '/' ? '/' : normalizePartName(part.source), part);\n }\n return map;\n}\n","import {\n checkPartNameCollisions,\n CONTENT_TYPES_PART,\n CONTENT_TYPE,\n FONT_DATA_CONTENT_TYPE,\n FONT_DATA_EXTENSION,\n partExtension,\n REL_TYPE,\n validatePartName,\n} from '@pptx-studio/opc';\nimport { attributeValue, childElements } from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation, PACKAGE_LOCATION, partLocation } from '../report/location.js';\nimport { readRelsParts, resolveTarget } from '../rels.js';\n\n/**\n * `V001` … `V005`: the container.\n *\n * These five run before any markup is looked at, and they are the ones whose\n * failure mode is \"PowerPoint declines to open the file at all\" rather than\n * \"the slide renders wrong\". The package layer has no partial credit: a part\n * with no content type is not a part with an unknown type, it is a stream\n * nothing is allowed to interpret.\n */\n\n/** Every part resolves to a content type. */\nexport function v001ContentTypeCoverage(ctx: Context): void {\n for (const part of ctx.parts()) {\n if (ctx.contentType(part) !== undefined) continue;\n const extension = partExtension(part);\n ctx.add(\n 'V001',\n partLocation(part),\n 'no content type: nothing in [Content_Types].xml covers it. Add an Override for the part, ' +\n (extension === ''\n ? 'or give it an extension a Default covers.'\n : 'or a Default for the \"' + extension + '\" extension.'),\n );\n }\n}\n\n/**\n * The content-type map holds together.\n *\n * Four separate things, one rule, because they are one question - \"does this\n * map say exactly one thing about every part\" - and a caller who has to\n * remember four rule ids to know whether their content types are sound is a\n * caller who will remember three.\n */\nexport function v002ContentTypeMap(ctx: Context): void {\n const document = ctx.contentTypesDocument();\n\n // Duplicates are only visible in the markup. See `Context.contentTypesDocument`.\n if (document === null) {\n if (ctx.archive === null) {\n // Said out loud rather than quietly skipped. The rest of this rule still\n // runs, so it is a narrower check than it looks like, and a report that\n // does not say so is a report that overstates itself.\n ctx.problem(\n CONTENT_TYPES_PART,\n 'not available: only a PartStore was supplied, so V002 checked the parsed map and not ' +\n 'the markup. A duplicate <Default> or <Override> is visible only in the markup.',\n );\n } else {\n ctx.add(\n 'V002',\n partLocation(CONTENT_TYPES_PART),\n 'the content-type stream is missing or would not parse.',\n );\n }\n } else {\n const seenDefault = new Map<string, number>();\n const seenOverride = new Map<string, number>();\n for (const child of childElements(document.root)) {\n if (child.local === 'Default') {\n const extension = (attributeValue(child, 'Extension') ?? '').toLowerCase();\n const count = (seenDefault.get(extension) ?? 0) + 1;\n seenDefault.set(extension, count);\n if (count === 2) {\n // M2.5 is unconditional and PowerPoint enforces it literally: two\n // `<Default>`s for one extension are refused with `0x80CB8000` even\n // when the two elements are byte-identical.\n ctx.add(\n 'V002',\n elementLocation(CONTENT_TYPES_PART, child),\n 'the \"' +\n extension +\n '\" extension has two <Default> entries. PowerPoint refuses a duplicate even when ' +\n 'the two agree.',\n );\n }\n } else if (child.local === 'Override') {\n const partName = attributeValue(child, 'PartName') ?? '';\n const key = partName.toLowerCase();\n const count = (seenOverride.get(key) ?? 0) + 1;\n seenOverride.set(key, count);\n if (count === 2) {\n ctx.add(\n 'V002',\n elementLocation(CONTENT_TYPES_PART, child),\n partName + ' has two <Override> entries.',\n );\n }\n if (partName !== '' && !ctx.store.has(partName)) {\n ctx.add(\n 'V002',\n elementLocation(CONTENT_TYPES_PART, child),\n 'an <Override> names ' + partName + ', which is not in the package.',\n );\n }\n }\n }\n }\n\n // The `fntdata` Default. Omitting it is the canonical \"PowerPoint found a\n // problem with content\" bug, and it is invisible until a user without the\n // font opens the file - the deck is otherwise complete and the relationship,\n // the `p:embeddedFont` entry and the part itself are all correct.\n const fontParts = ctx\n .parts()\n .filter((part) => partExtension(part).toLowerCase() === FONT_DATA_EXTENSION);\n if (fontParts.length > 0) {\n const declared = ctx.store.contentTypes.defaults.find(\n (entry) => entry.extension.toLowerCase() === FONT_DATA_EXTENSION,\n );\n if (declared === undefined) {\n ctx.add(\n 'V002',\n partLocation(CONTENT_TYPES_PART),\n 'the package has ' +\n String(fontParts.length) +\n ' .fntdata part(s) and no <Default Extension=\"fntdata\" ContentType=\"' +\n FONT_DATA_CONTENT_TYPE +\n '\"/>. PowerPoint reports the file as having a problem with its content.',\n );\n } else if (declared.contentType.toLowerCase() !== FONT_DATA_CONTENT_TYPE.toLowerCase()) {\n ctx.add(\n 'V002',\n partLocation(CONTENT_TYPES_PART),\n 'the fntdata Default is typed \"' +\n declared.contentType +\n '\"; embedded fonts are \"' +\n FONT_DATA_CONTENT_TYPE +\n '\".',\n );\n }\n }\n}\n\n/** No directory entries, no ZIP64 record. */\nexport function v003ArchiveShape(ctx: Context): void {\n const archive = ctx.archive;\n if (archive === null) return;\n\n for (const entry of archive.entries) {\n if (!entry.isDirectory) continue;\n ctx.add(\n 'V003',\n PACKAGE_LOCATION,\n 'the archive carries a directory entry, \"' +\n entry.name +\n '\". No OPC part name may end in a slash, so nothing in the package can name it.',\n );\n }\n\n if (ctx.bytes !== null && hasZip64Locator(ctx.bytes)) {\n ctx.add(\n 'V003',\n PACKAGE_LOCATION,\n 'the archive carries a ZIP64 end-of-central-directory locator. Our writer emits ZIP32 ' +\n 'only, so one in a package we produced means a size or offset field overflowed.',\n );\n }\n}\n\n/**\n * The ZIP64 locator signature, searched backwards from the end.\n *\n * The locator sits immediately before the end-of-central-directory record,\n * which is within 64 KB + 22 bytes of the end once a comment is allowed for.\n * Same computation `@pptx-studio/census` makes; duplicated rather than shared\n * because `census` is a sibling at layer 1 and depending on it to answer one\n * boolean would put a whole feature scanner in the export path.\n */\nfunction hasZip64Locator(bytes: Uint8Array): boolean {\n if (bytes.byteLength < 20) return false;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const from = Math.max(0, bytes.byteLength - 0x10000 - 40);\n for (let at = bytes.byteLength - 20; at >= from; at--) {\n if (view.getUint32(at, true) === 0x07064b50) return true;\n }\n return false;\n}\n\n/**\n * Part names, with `M1.8` raised from warning to fatal.\n *\n * `@pptx-studio/opc` rates a percent-escape of an unreserved character a\n * warning, and that is right *there*: the package layer has to open what it is\n * given, and a file that arrives with `%5F` in a part name is a file the user\n * still wants to see. Here we are about to write one, and PowerPoint refuses\n * it with `0x808D1005` - measured nine for nine on one-name packages. Raising\n * the severity at the point of writing rather than at the point of reading is\n * the whole shape of the read-leniently/write-strictly split this project uses\n * everywhere.\n */\nexport function v004PartNames(ctx: Context): void {\n for (const part of ctx.parts()) {\n for (const violation of validatePartName(part)) {\n // Every violation, warning or not. `validatePartName` grades severity for\n // a *reader*, which has to open what it is given; here we are about to\n // write one, and a part name that is merely non-conformant is a part name\n // we should not be emitting. An odd name a deck arrived with is not\n // trapped by this - it comes back `inherited` and does not block the\n // export. See `report.ts`.\n ctx.add('V004', partLocation(part), violation.rule + ': ' + violation.message);\n }\n }\n\n for (const collision of checkPartNameCollisions([...ctx.parts()])) {\n ctx.add('V004', partLocation(collision.names[0]), collision.rule + ': ' + collision.message);\n }\n}\n\n/** The main presentation part: exactly one, of a type that matches the file. */\nconst MAIN_PART_TYPES = new Set<string>([\n CONTENT_TYPE.presentation,\n CONTENT_TYPE.template,\n CONTENT_TYPE.slideshow,\n 'application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml',\n 'application/vnd.ms-powerpoint.template.macroEnabled.main+xml',\n 'application/vnd.ms-powerpoint.slideshow.macroEnabled.main+xml',\n]);\n\nexport function v005MainPart(ctx: Context): void {\n const rootRels = readRelsParts(ctx).find((rels) => rels.source === '/');\n if (rootRels === undefined) {\n ctx.add(\n 'V005',\n partLocation('/_rels/.rels'),\n 'the package has no root relationship part. It is the only way in to a .pptx; without it ' +\n 'nothing can be reached and PowerPoint reports the file as corrupted and unreadable.',\n );\n return;\n }\n\n const officeDocuments = rootRels.relationships.filter(\n (rel) => rel.type === REL_TYPE.officeDocument,\n );\n if (officeDocuments.length === 0) {\n ctx.add(\n 'V005',\n partLocation(rootRels.partName),\n 'no officeDocument relationship. Nothing names the main presentation part.',\n );\n return;\n }\n if (officeDocuments.length > 1) {\n for (const rel of officeDocuments.slice(1)) {\n ctx.add(\n 'V005',\n elementLocation(rootRels.partName, rel.element),\n 'a second officeDocument relationship (' +\n rel.id +\n ' -> ' +\n rel.target +\n '). Exactly one part is the main part.',\n );\n }\n }\n\n const main = officeDocuments[0]!;\n const resolved = resolveTarget(rootRels.source, main.target);\n if (resolved.part === null) {\n ctx.add(\n 'V005',\n elementLocation(rootRels.partName, main.element),\n 'the officeDocument target does not resolve: ' + (resolved.failure ?? 'unknown reason'),\n );\n return;\n }\n if (!ctx.store.has(resolved.part)) {\n ctx.add(\n 'V005',\n elementLocation(rootRels.partName, main.element),\n 'the officeDocument target ' + resolved.part + ' is not in the package.',\n );\n return;\n }\n\n const contentType = ctx.contentType(resolved.part);\n if (contentType === undefined || !MAIN_PART_TYPES.has(contentType)) {\n ctx.add(\n 'V005',\n partLocation(resolved.part),\n 'the main part is typed ' +\n (contentType === undefined ? '(nothing)' : '\"' + contentType + '\"') +\n ', which is not a PresentationML main-part type. PowerPoint also checks this against ' +\n 'the file extension and refuses the pair when they disagree, which is why a ' +\n 'macro-enabled deck has to be written .pptm.',\n );\n }\n}\n","import {\n CONTENT_TYPE,\n isRelationshipPartName,\n isValidRelationshipId,\n normalizePartName,\n REL_TYPE,\n} from '@pptx-studio/opc';\nimport {\n attributeNamespaceOf,\n descendantElements,\n NS,\n type XAttribute,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { attributeLocation, elementLocation, partLocation } from '../report/location.js';\nimport { bySource, readRelsParts, resolveTarget, type RelsPart } from '../rels.js';\n\n/**\n * `V006` … `V009`: the relationship graph.\n *\n * The graph is where a `.pptx` keeps almost everything that is not text. A\n * slide does not name its layout, a picture does not name its image, and a\n * chart does not name its workbook: each of them names an `rId`, and the `rId`\n * means something only inside one `.rels` part. Three consequences run through\n * all four rules below.\n *\n * **Ids are scoped, not global.** `rId3` in `slide1.xml.rels` and `rId3` in\n * `slide2.xml.rels` are unrelated. A global id registry is not an optimisation,\n * it is a bug, and it is a bug that works fine on every one-slide test deck.\n *\n * **Dangling is fatal; orphaned is harmless.** A reference to a relationship\n * that is not there, or a relationship to a part that is not there, breaks the\n * file. A relationship nothing references does not. That asymmetry is what\n * decides the direction media garbage collection is allowed to be aggressive\n * in, and getting it backwards is how a \"clean-up\" pass deletes the layouts a\n * user was about to switch to.\n *\n * **Targets resolve against the source part's folder.** Not the package root,\n * and not the `.rels` file's own folder.\n */\n\n/**\n * Attributes in the relationship namespace that name a relationship id.\n *\n * All of them do, in practice - `r:id`, `r:embed`, `r:link`, `r:pict`,\n * `r:dm`, `r:lo`, `r:qs`, `r:cs`, `r:href` and the rest. Rather than list the\n * ones we know, this rule matches on the *namespace*, so an attribute from a\n * schema we have not read yet is checked rather than skipped. The two things\n * that must not be treated as ids are handled explicitly below.\n */\nfunction isRelationshipReference(owner: XElement, attr: XAttribute): boolean {\n if (attr.prefix === '' || attr.prefix === 'xmlns') return false;\n // `r:` is conventional and not guaranteed, so the prefix is resolved rather\n // than compared. A part is free to bind the relationship namespace to any\n // prefix, and matching on the string `r` would silently stop checking one\n // that did.\n return attributeNamespaceOf(owner, attr) === NS.r;\n}\n\n/** Every `r:*` reference resolves in its own part's `.rels`. */\nexport function v006ReferencesResolve(ctx: Context): void {\n const relsBySource = bySource(readRelsParts(ctx));\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n\n const rels = relsBySource.get(normalizePartName(part));\n const known = new Set((rels?.relationships ?? []).map((rel) => rel.id));\n\n for (const element of descendantElements(document.root)) {\n for (const attr of element.attributes) {\n if (!isRelationshipReference(element, attr)) continue;\n // An empty value is not a dangling reference, it is the absence of one.\n // `<a:hlinkClick r:id=\"\" action=\"ppaction://noaction\"/>` is what\n // PowerPoint writes for an action with no target, and it is common.\n if (attr.value === '') continue;\n if (known.has(attr.value)) continue;\n ctx.add(\n 'V006',\n attributeLocation(part, element, attr.qname),\n rels === undefined\n ? '<' +\n element.qname +\n ' ' +\n attr.qname +\n '=\"' +\n attr.value +\n '\"> refers to a relationship, but this part has no .rels at all.'\n : '<' +\n element.qname +\n ' ' +\n attr.qname +\n '=\"' +\n attr.value +\n '\"> names a relationship that ' +\n rels.partName +\n ' does not declare. Ids are scoped to one .rels part; this one has ' +\n (known.size === 0 ? 'none' : [...known].sort().join(', ')) +\n '.',\n );\n }\n }\n }\n}\n\n/** Relationship ids are unique within a `.rels` and are `xsd:ID`s. */\nexport function v007RelationshipIds(ctx: Context): void {\n for (const rels of readRelsParts(ctx)) {\n const seen = new Map<string, number>();\n for (const rel of rels.relationships) {\n if (rel.id === '') {\n ctx.add('V007', elementLocation(rels.partName, rel.element), 'a <Relationship> has no Id.');\n continue;\n }\n if (!isValidRelationshipId(rel.id)) {\n ctx.add(\n 'V007',\n elementLocation(rels.partName, rel.element),\n 'Id=\"' +\n rel.id +\n '\" is not an xsd:ID. An xsd:ID is an XML NCName: it cannot begin with a digit and ' +\n 'cannot contain a space or a colon.',\n );\n }\n const count = (seen.get(rel.id) ?? 0) + 1;\n seen.set(rel.id, count);\n if (count === 2) {\n ctx.add(\n 'V007',\n elementLocation(rels.partName, rel.element),\n 'Id=\"' +\n rel.id +\n '\" appears twice. Which target a reference to it means would be undecidable.',\n );\n }\n }\n }\n}\n\n/** Internal targets resolve, stay inside the package, and name a part that exists. */\nexport function v008TargetsResolve(ctx: Context): void {\n for (const rels of readRelsParts(ctx)) {\n for (const rel of rels.relationships) {\n if (rel.targetMode === 'External') continue;\n if (rel.targetMode !== 'Internal') {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n 'TargetMode=\"' + rel.targetMode + '\" is neither Internal nor External.',\n );\n continue;\n }\n if (rel.target === '') {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n rel.id + ' has an empty Target.',\n );\n continue;\n }\n const resolved = resolveTarget(rels.source, rel.target);\n if (resolved.part === null) {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n rel.id +\n ' -> \"' +\n rel.target +\n '\" does not resolve against ' +\n rels.source +\n ': ' +\n (resolved.failure ?? 'unknown reason'),\n );\n continue;\n }\n if (!ctx.store.has(resolved.part)) {\n ctx.add(\n 'V008',\n elementLocation(rels.partName, rel.element),\n rel.id +\n ' -> ' +\n resolved.part +\n ' names a part that is not in the package. A dangling relationship is fatal where an ' +\n 'orphaned one is harmless, which is why garbage collection may only ever be ' +\n 'aggressive in the other direction.',\n );\n }\n }\n }\n}\n\n/** The chartex content type. Not in `CONTENT_TYPE`: it is Microsoft's, not ECMA's. */\nconst CHART_EX_CONTENT_TYPE = 'application/vnd.ms-office.chartex+xml';\n\n/**\n * The ECMA `customXml` relationship type.\n *\n * A `p:contentPart` reached by *this* type is a whole-package refusal, while\n * the Microsoft 2010 type of the same name opens - and so do two relationship\n * types that make no sense at all. PowerPoint validates that one type rather\n * than types in general, which is a strange enough finding that it is worth\n * writing the constant down beside the rule that uses it.\n */\nconst REL_CUSTOM_XML_ECMA =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml';\n\n/** Elements whose `r:` attribute means \"this is a media object's target\". */\nconst MEDIA_REFERENCE_ELEMENTS = new Set(['audioFile', 'videoFile', 'media']);\n\n/**\n * The edges a part must have, and the ones it must not.\n *\n * Four findings, none of them in any schema. See the rule's `why` in\n * `rules.ts` for the bisections; the code below is deliberately a table read\n * against the package rather than four separate walks.\n */\nexport function v009RequiredEdges(ctx: Context): void {\n const relsParts = readRelsParts(ctx);\n const relsBySource = bySource(relsParts);\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const contentType = ctx.contentType(part);\n const rels = relsBySource.get(normalizePartName(part));\n\n if (contentType === CONTENT_TYPE.slide) {\n requireExactlyOne(ctx, part, rels, REL_TYPE.slideLayout, CONTENT_TYPE.slideLayout, 'layout');\n } else if (contentType === CONTENT_TYPE.slideLayout) {\n requireExactlyOne(ctx, part, rels, REL_TYPE.slideMaster, CONTENT_TYPE.slideMaster, 'master');\n } else if (contentType === CHART_EX_CONTENT_TYPE) {\n // A `cx:chartSpace` with no `.rels` of its own is a whole-package\n // refusal, including one PowerPoint wrote itself. The classic\n // `c:chartSpace` needs neither of these.\n for (const [type, label] of [\n ['http://schemas.microsoft.com/office/2011/relationships/chartStyle', 'chartStyle'],\n [\n 'http://schemas.microsoft.com/office/2011/relationships/chartColorStyle',\n 'chartColorStyle',\n ],\n ] as const) {\n if ((rels?.relationships ?? []).some((rel) => rel.type === type)) continue;\n ctx.add(\n 'V009',\n partLocation(part),\n 'a chartex part with no ' +\n label +\n ' relationship. Unlike a classic c:chartSpace, which needs neither, a cx:chartSpace ' +\n 'without both is a whole-package refusal.',\n );\n }\n }\n }\n\n // `p:contentPart` reached by the ECMA customXml type.\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n const rels = relsBySource.get(normalizePartName(part));\n if (rels === undefined) continue;\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'contentPart') continue;\n for (const attr of element.attributes) {\n if (attr.local !== 'id' || attr.prefix === '') continue;\n const relationship = rels.relationships.find((rel) => rel.id === attr.value);\n if (relationship?.type !== REL_CUSTOM_XML_ECMA) continue;\n ctx.add(\n 'V009',\n attributeLocation(part, element, attr.qname),\n 'a <' +\n element.qname +\n '> reached by the ECMA customXml relationship type is a whole-package refusal. The ' +\n 'Microsoft 2010 type of the same name opens; PowerPoint validates this one type ' +\n 'rather than types in general.',\n );\n }\n }\n }\n\n checkSharedMedia(ctx, relsBySource);\n}\n\nfunction requireExactlyOne(\n ctx: Context,\n part: string,\n rels: RelsPart | undefined,\n type: string,\n targetContentType: string,\n label: string,\n): void {\n const matching = (rels?.relationships ?? []).filter((rel) => rel.type === type);\n if (matching.length !== 1) {\n ctx.add(\n 'V009',\n partLocation(part),\n 'has ' +\n String(matching.length) +\n ' ' +\n label +\n ' relationship(s); it needs exactly one. The binding lives only in the .rels part - ' +\n 'nothing in the part itself names its ' +\n label +\n ' - so zero and two are both whole-package refusals.',\n );\n return;\n }\n const rel = matching[0]!;\n const resolved = resolveTarget(rels!.source, rel.target);\n if (resolved.part === null || !ctx.store.has(resolved.part)) {\n // Reported by `V008` as a dangling target; the extra thing this rule knows\n // is that it is *this* edge, which is the one that cannot be missing.\n ctx.add(\n 'V009',\n elementLocation(rels!.partName, rel.element),\n 'the ' + label + ' relationship points at a part that is not in the package.',\n );\n return;\n }\n const actual = ctx.contentType(resolved.part);\n if (actual !== targetContentType) {\n ctx.add(\n 'V009',\n elementLocation(rels!.partName, rel.element),\n 'the ' +\n label +\n ' relationship resolves to ' +\n resolved.part +\n ', which is typed ' +\n (actual === undefined ? '(nothing)' : '\"' + actual + '\"') +\n ' rather than \"' +\n targetContentType +\n '\". One pointing at a master instead was built as a single change and refused.',\n );\n }\n}\n\n/**\n * A media part that is both a transition sound and a media object's target.\n *\n * The only refusal we have measured whose message is \"PowerPoint could not open\n * the file\" rather than \"the file or directory is corrupted and unreadable\" -\n * which is worth recording, because the message is the only signal there is.\n * Two copies of the same bytes open; one shared copy does not.\n */\nfunction checkSharedMedia(ctx: Context, relsBySource: ReadonlyMap<string, RelsPart>): void {\n const asTransitionSound = new Map<string, string>();\n const asMediaObject = new Map<string, string>();\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n const rels = relsBySource.get(normalizePartName(part));\n if (rels === undefined) continue;\n\n for (const element of descendantElements(document.root)) {\n const isSound = element.local === 'snd';\n const isMedia = MEDIA_REFERENCE_ELEMENTS.has(element.local);\n if (!isSound && !isMedia) continue;\n for (const attr of element.attributes) {\n if (attr.prefix === '' || attr.value === '') continue;\n if (attr.local !== 'embed' && attr.local !== 'link') continue;\n const rel = rels.relationships.find((r) => r.id === attr.value);\n if (rel === undefined || rel.targetMode === 'External') continue;\n const target = resolveTarget(rels.source, rel.target).part;\n if (target === null) continue;\n (isSound ? asTransitionSound : asMediaObject).set(normalizePartName(target), part);\n }\n }\n }\n\n for (const [target, soundOwner] of asTransitionSound) {\n const mediaOwner = asMediaObject.get(target);\n if (mediaOwner === undefined) continue;\n ctx.add(\n 'V009',\n partLocation(target),\n 'is both a transition sound (from ' +\n soundOwner +\n ') and a media object target (from ' +\n mediaOwner +\n '). Two copies of the same bytes open; one shared copy is a refusal.',\n );\n }\n}\n","import { isRelationshipPartName } from '@pptx-studio/opc';\nimport {\n attributeValue,\n childElements,\n childRanks,\n descendantElements,\n elementKey,\n isSchemaNamespace,\n namespaceOf,\n outOfOrderChildren,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation, xpathOf } from '../report/location.js';\n\n/**\n * `V010` … `V012`: where children are allowed to be.\n *\n * OOXML complex types are `xsd:sequence` almost everywhere, and this is the\n * category with the best-attested consequence in the whole appendix: Microsoft's\n * own Open XML SDK shipped a regression that swapped two elements in\n * `slideMaster1.xml`, changed nothing else, and PowerPoint refused the file.\n *\n * The ranks come from `@pptx-studio/xml`'s generated table, which is built from\n * the ECMA-376 Transitional schemas and checked against 194 148 elements\n * PowerPoint wrote. That second number is what makes the rule safe to make\n * fatal: a table generated from a standard and never compared with reality\n * would be a very confident way to reject files that work.\n *\n * The three rules divide the question by what the table can and cannot see:\n *\n * - `V010` - the child is in the model but in the wrong place.\n * - `V011` - `extLst` last, which has to hold in the places the table cannot\n * rank at all.\n * - `V012` - the child is not in the model.\n *\n * `V010` skips anything it cannot rank, which is correct for ordering and is\n * exactly the blind spot `V012` exists to cover.\n */\n\n/** Children in schema-sequence order. */\nexport function v010SchemaOrder(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n for (const problem of outOfOrderChildren(element)) {\n ctx.add(\n 'V010',\n { part, xpath: xpathOf(element), offset: problem.at },\n problem.detail +\n '. OOXML complex types are xsd:sequence and PowerPoint enforces the order literally.',\n );\n }\n });\n}\n\n/**\n * `extLst` is last, and every `a:ext` names its extension.\n *\n * There is exactly one type in the whole generated table where `extLst` is not\n * last: `p:control`, whose model is `extLst` then `pic`. That is not an\n * exception worth handling gracefully - `V025` refuses `p:control` outright,\n * because PowerPoint refuses it in all eight forms we tried - but it is skipped\n * here rather than reported twice.\n */\nexport function v011ExtLstLast(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'extLst') return;\n const parent = element.parent;\n if (parent === undefined || parent.local === 'control') return;\n\n const siblings = childElements(parent);\n const last = siblings[siblings.length - 1];\n if (last !== element) {\n ctx.add(\n 'V011',\n elementLocation(part, element),\n '<' +\n element.qname +\n '> is followed by <' +\n (last?.qname ?? '?') +\n '> inside <' +\n parent.qname +\n '>. An extension list is last in every type that has one.',\n );\n }\n\n for (const ext of childElements(element)) {\n if (ext.local !== 'ext') continue;\n const uri = attributeValue(ext, 'uri');\n if (uri !== undefined && uri !== '') continue;\n ctx.add(\n 'V011',\n elementLocation(part, ext),\n '<' +\n ext.qname +\n '> has no @uri. The uri is the only identity an extension has, and the contract for ' +\n 'extension markup is that it is carried through untouched *keyed by that uri* - so one ' +\n 'without it cannot be preserved, only guessed at.',\n );\n }\n });\n}\n\n/**\n * No child in a parent whose content model has no place for it.\n *\n * Deliberately conservative in four ways, because a false positive here refuses\n * a file somebody wanted:\n *\n * - only parents the generated table knows are checked, and `childRanks`\n * returns `undefined` for every open (`xsd:any`) type, so `a:ext`,\n * `p:ext` and `a:graphicData` - the three places the plan forbids us to\n * rebuild - are never looked at;\n * - **only children in the four namespaces the table was generated from.**\n * This is the one the corpus taught us. `childRanks` collapses \"the schema\n * forbids this here\" and \"we have never read this schema\" into the same\n * `undefined`, which is right for a caller trying to insert a child and\n * catastrophic for one trying to judge an existing one: without the\n * namespace test, the rule fired on forty `mc:AlternateContent` elements,\n * on `a14:m`, on `p14:honeycomb` and on `a37-mce`'s deliberate `zz:` markup -\n * which is `mc:Ignorable` extension markup doing exactly what it exists for;\n * - `mc:Choice` and `mc:Fallback` are unrankable parents, so their contents\n * fall out for free.\n */\nexport function v012UnexpectedChild(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n const ranks = childRanks(element);\n if (ranks === undefined) return;\n for (const child of childElements(element)) {\n if (!isSchemaNamespace(namespaceOf(child))) continue;\n const key = elementKey(child);\n if (key === undefined || ranks.has(key)) continue;\n ctx.add(\n 'V012',\n elementLocation(part, child),\n '<' +\n child.qname +\n '> is not a child <' +\n element.qname +\n '> admits. `a:ahXY` or `a:cxn` placed directly under `a:custGeom`, without its ' +\n '`a:ahLst`/`a:cxnLst` wrapper, is the case that made this a rule: a whole-package ' +\n 'refusal that the ordering rule cannot see, because an unrankable child is skipped ' +\n 'there rather than reported.',\n );\n }\n });\n}\n\n/**\n * Every element of every XML part, once.\n *\n * The three rules above each want the same walk. Sharing it means one traversal\n * of the package instead of three, and - more usefully - one place where the\n * decision \"which parts does an order rule apply to\" is made. Relationship\n * parts are excluded: `Relationships` is not in any schema we generate from, so\n * every one of its children would be unrankable and the rules would be checking\n * nothing while appearing to check everything.\n */\nfunction forEachElement(ctx: Context, visit: (part: string, element: XElement) => void): void {\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n for (const element of descendantElements(document.root)) visit(part, element);\n }\n}\n","import { CONTENT_TYPE, isRelationshipPartName } from '@pptx-studio/opc';\nimport {\n attribute,\n childElements,\n descendantElements,\n namespaceOf,\n NS,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation } from '../report/location.js';\n\n/**\n * `V013` … `V017`: children and attributes that are not optional.\n *\n * Every one of these is a `minOccurs` the schema states plainly, and every one\n * is broken the same way: by an editor deleting the last of something. The last\n * paragraph goes and a `p:txBody` is left with no `a:p`; a shape is dragged out\n * of a group and the group's `p:grpSpPr` is dropped with it. That is why these\n * are separate rules from the ordering ones even though a missing child and a\n * misplaced child are both \"the sequence is wrong\": the messages have to say\n * *add this*, not *move this*, and they have to fire on the parent rather than\n * on a child that is not there to point at.\n */\n\n/** The twelve attributes of `CT_ColorMapping`. All required, no defaults. */\nconst CLR_MAP_ATTRIBUTES = [\n 'bg1',\n 'tx1',\n 'bg2',\n 'tx2',\n 'accent1',\n 'accent2',\n 'accent3',\n 'accent4',\n 'accent5',\n 'accent6',\n 'hlink',\n 'folHlink',\n] as const;\n\n/** `p:presentation` carries `p:notesSz`. */\nexport function v013NotesSize(ctx: Context): void {\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n const root = document.root;\n if (root.local !== 'presentation' || namespaceOf(root) !== NS.p) continue;\n\n if (childElements(root).some((child) => child.local === 'notesSz')) continue;\n ctx.add(\n 'V013',\n elementLocation(part, root),\n 'no <p:notesSz>. In CT_Presentation p:sldSz is [0..1] and p:notesSz is [1..1] - the ' +\n 'asymmetry is the whole of this rule, and a generator that treats the two the same way ' +\n 'writes a presentation part that is missing a required child.',\n );\n }\n}\n\n/** `p:clrMap` carries all twelve attributes. */\nexport function v014ColorMap(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'clrMap' || namespaceOf(element) !== NS.p) return;\n const missing = CLR_MAP_ATTRIBUTES.filter((name) => attribute(element, name) === undefined);\n if (missing.length === 0) return;\n ctx.add(\n 'V014',\n elementLocation(part, element),\n 'the colour map is missing ' +\n missing.join(', ') +\n '. All twelve attributes of CT_ColorMapping are required and none has a default; a ' +\n 'partial map is not a map with a gap, it is an invalid element - and it is the element ' +\n 'that decides what bg1 and tx1 resolve to everywhere in the deck.',\n );\n });\n}\n\n/** `p:spTree` begins with `p:nvGrpSpPr` then `p:grpSpPr`. */\nexport function v015ShapeTreePrologue(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'spTree' || namespaceOf(element) !== NS.p) return;\n const children = childElements(element);\n if (children[0]?.local !== 'nvGrpSpPr' || children[1]?.local !== 'grpSpPr') {\n ctx.add(\n 'V015',\n elementLocation(part, element),\n 'a shape tree begins with <nvGrpSpPr> then <grpSpPr>, in that order, before any shape. ' +\n 'This one begins ' +\n (children.length === 0\n ? 'with nothing'\n : children\n .slice(0, 2)\n .map((child) => '<' + child.qname + '>')\n .join(' then ')) +\n '. A shape tree is a group shape, and CT_GroupShape requires both even when the slide ' +\n 'is empty.',\n );\n }\n });\n}\n\n/** Every text body has `a:bodyPr` and at least one `a:p`. */\nexport function v016TextBody(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'txBody') return;\n const children = childElements(element);\n if (!children.some((child) => child.local === 'bodyPr')) {\n ctx.add(\n 'V016',\n elementLocation(part, element),\n '<' + element.qname + '> has no <a:bodyPr>. CT_TextBody requires it first.',\n );\n }\n if (!children.some((child) => child.local === 'p')) {\n ctx.add(\n 'V016',\n elementLocation(part, element),\n '<' +\n element.qname +\n '> has no <a:p>. CT_TextBody is [1..unbounded] paragraphs, and an empty paragraph is ' +\n 'not the same thing as no paragraph - a:endParaRPr is where an empty one gets its ' +\n 'height. This is what deleting the last paragraph in an editor produces.',\n );\n }\n });\n}\n\n/** `p:graphicFrame` carries `p:xfrm` and `a:graphic`. */\nexport function v017GraphicFrame(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'graphicFrame' || namespaceOf(element) !== NS.p) return;\n\n const xfrm = childElements(element).find((child) => child.local === 'xfrm');\n if (xfrm === undefined) {\n ctx.add(\n 'V017',\n elementLocation(part, element),\n 'no <p:xfrm>. Note the namespace: a graphic frame carries the PresentationML transform, ' +\n 'not the a:xfrm every other shape uses. It has no placeholder-inherited geometry path ' +\n 'either, which is why a rebound chart or table gets a copy of its layout transform ' +\n 'rather than having its own deleted.',\n );\n } else if (namespaceOf(xfrm) !== NS.p) {\n ctx.add(\n 'V017',\n elementLocation(part, xfrm),\n 'the transform here is <' +\n xfrm.qname +\n '>, in the DrawingML namespace. CT_GraphicalObjectFrame takes p:xfrm; a:xfrm in its ' +\n 'place is the same element name bound to the wrong schema.',\n );\n }\n\n // By local name and namespace, never by qname: `a:` is the conventional\n // prefix for DrawingML and not a guaranteed one, and a part that binds it\n // differently would silently stop being checked.\n const graphic = childElements(element).find(\n (child) => child.local === 'graphic' && namespaceOf(child) === NS.a,\n );\n if (graphic === undefined) {\n ctx.add(\n 'V017',\n elementLocation(part, element),\n 'no <a:graphic>. The frame is the wrapper; the graphic is the thing in it, and a frame ' +\n 'without one names no table, chart, diagram or OLE object at all.',\n );\n }\n });\n}\n\n/**\n * Presentation-family parts only.\n *\n * A `.pptx` carries whole foreign documents inside it - an embedded workbook\n * behind every chart, a Word document behind some OLE objects - and their parts\n * are XML with elements called `txBody` and `graphicFrame` in namespaces these\n * rules do not govern. Checking them would be applying PresentationML's\n * cardinalities to SpreadsheetML's schema, which is why every rule above tests\n * the namespace and not only the local name, and why the walk itself stops at\n * parts whose content type belongs to another format.\n */\nconst FOREIGN_CONTENT_TYPES = new Set<string>([\n CONTENT_TYPE.spreadsheet,\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml',\n]);\n\nfunction forEachElement(ctx: Context, visit: (part: string, element: XElement) => void): void {\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const contentType = ctx.contentType(part);\n if (contentType !== undefined && FOREIGN_CONTENT_TYPES.has(contentType)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n for (const element of descendantElements(document.root)) visit(part, element);\n }\n}\n\n/** Exported for `refusal-rules.ts`, which walks the same parts for the same reason. */\nexport { forEachElement, FOREIGN_CONTENT_TYPES };\n","import {\n CONTENT_TYPE,\n isRelationshipPartName,\n normalizePartName,\n REL_TYPE,\n} from '@pptx-studio/opc';\nimport {\n attributeValue,\n descendantElements,\n namespaceOf,\n NS,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { attributeLocation, elementLocation } from '../report/location.js';\nimport { bySource, readRelsParts, resolveTarget } from '../rels.js';\n\n/**\n * `V018` … `V021`: four identifier spaces, and never one allocator.\n *\n * A presentation has four kinds of id and they do not share a rule between\n * them. Slide ids start at 256 and stop at 2147483647. Master and layout ids\n * start at 2147483648, and - the part no schema says - come out of **one**\n * counter shared between them. Shape ids are unique inside a part and free to\n * repeat across parts. Placeholder indices are not identifiers at all; they are\n * a join key against another part.\n *\n * Every one of those is a way to break a file that looks like a way to be\n * tidy. Renumbering shape ids to be unique across the deck is the obvious\n * example: it is more consistent, it is what a database would do, and it\n * detaches every `p:custDataLst`, VML `@spid` and animation target that names\n * the old number.\n */\n\nconst SLIDE_ID_MIN = 256;\nconst SLIDE_ID_MAX = 2147483647;\nconst SHEET_ID_MIN = 2147483648;\nconst SHEET_ID_MAX = 4294967295;\n\n/** An `@id` read as a base-10 integer, or `null` when it is not one. */\nfunction integerAttribute(element: XElement, name: string): number | null {\n const raw = attributeValue(element, name);\n if (raw === undefined || !/^\\d+$/.test(raw.trim())) return null;\n return Number(raw.trim());\n}\n\n/** `p:sldId/@id` is 256…2147483647 and unique. */\nexport function v018SlideIds(ctx: Context): void {\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n const seen = new Map<number, XElement>();\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'sldId' || namespaceOf(element) !== NS.p) continue;\n const raw = attributeValue(element, 'id');\n const value = integerAttribute(element, 'id');\n if (value === null) {\n ctx.add(\n 'V018',\n attributeLocation(part, element, 'id'),\n raw === undefined\n ? '<p:sldId> has no @id.'\n : '@id=\"' + raw + '\" is not a base-10 unsigned integer.',\n );\n continue;\n }\n if (value < SLIDE_ID_MIN || value > SLIDE_ID_MAX) {\n ctx.add(\n 'V018',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is outside ST_SlideId, which is ' +\n String(SLIDE_ID_MIN) +\n '…' +\n String(SLIDE_ID_MAX) +\n '. The floor is the part that gets missed: nothing about a first slide suggests its ' +\n 'id should start at 256.',\n );\n }\n if (seen.has(value)) {\n ctx.add(\n 'V018',\n attributeLocation(part, element, 'id'),\n '@id=' + String(value) + ' is used twice in this slide list.',\n );\n } else {\n seen.set(value, element);\n }\n }\n }\n}\n\n/**\n * Master and layout ids share one number space.\n *\n * The uniqueness check runs across the whole package rather than per part,\n * because `p:sldMasterId` lives in `ppt/presentation.xml` and `p:sldLayoutId`\n * lives in each master's own `p:sldLayoutIdLst` - so a collision between the\n * two is invisible to anything that validates one part at a time. That is\n * exactly how `a12-masters` was written wrong: a chassis numbering masters and\n * layouts from two counters is indistinguishable from correct with one master\n * and collides on the second.\n */\nexport function v019SheetIds(ctx: Context): void {\n const seen = new Map<number, string>();\n\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n for (const element of descendantElements(document.root)) {\n const isMaster = element.local === 'sldMasterId';\n const isLayout = element.local === 'sldLayoutId';\n if ((!isMaster && !isLayout) || namespaceOf(element) !== NS.p) continue;\n\n const raw = attributeValue(element, 'id');\n const value = integerAttribute(element, 'id');\n if (value === null) {\n // `@id` is optional on both in the schema. PowerPoint always writes\n // one, and a list entry without one cannot collide with anything, so\n // this is only reported when the attribute is present and unreadable.\n if (raw !== undefined) {\n ctx.add(\n 'V019',\n attributeLocation(part, element, 'id'),\n '@id=\"' + raw + '\" is not a base-10 unsigned integer.',\n );\n }\n continue;\n }\n if (value < SHEET_ID_MIN || value > SHEET_ID_MAX) {\n ctx.add(\n 'V019',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is outside ' +\n (isMaster ? 'ST_SlideMasterId' : 'ST_SlideLayoutId') +\n ', which is ' +\n String(SHEET_ID_MIN) +\n ' and up.',\n );\n continue;\n }\n const previous = seen.get(value);\n if (previous !== undefined) {\n ctx.add(\n 'V019',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is already used by ' +\n previous +\n '. Master and layout ids are one number space, not two: PowerPoint allocates them ' +\n 'from a single running counter - master, its layouts, next master, its layouts - and ' +\n 'refuses a package that does not.',\n );\n } else {\n seen.set(value, '<' + element.qname + '> in ' + part);\n }\n }\n }\n}\n\n/**\n * The `mc:Choice` / `mc:Fallback` ancestors of an element, outermost first.\n *\n * Two shapes in different branches of the same `mc:AlternateContent` never\n * exist in the same document: a consumer picks one branch and the other is not\n * there. So they may carry the same `@id`, and PowerPoint's own writer does\n * exactly that - `a22-chartex` has a `p:graphicFrame` with `id=\"10\"` in the\n * `mc:Choice` and the `p:pic` that stands in for it, also `id=\"10\"`, in the\n * `mc:Fallback`. Reporting that as a duplicate would fire on files PowerPoint\n * wrote, which is the corpus's whole job to prevent.\n */\nfunction branchPath(element: XElement): XElement[] {\n const path: XElement[] = [];\n for (let node = element.parent; node !== undefined; node = node.parent) {\n if (node.local === 'Choice' || node.local === 'Fallback') path.push(node);\n }\n return path.reverse();\n}\n\n/**\n * True when two elements can never both be present.\n *\n * They cannot when their branch paths diverge at some depth *into two branches\n * of the same `mc:AlternateContent`*. Diverging into branches of two different\n * `mc:AlternateContent` elements is not exclusion - both are chosen, and both\n * sets of shapes are on the slide together.\n */\nfunction mutuallyExclusive(a: readonly XElement[], b: readonly XElement[]): boolean {\n const depth = Math.min(a.length, b.length);\n for (let i = 0; i < depth; i++) {\n if (a[i] === b[i]) continue;\n return a[i]!.parent === b[i]!.parent;\n }\n return false;\n}\n\n/**\n * `p:cNvPr/@id` is unique within its part and reads as a positive signed\n * 32-bit integer.\n *\n * PresentationML only, which is narrower than \"every element called `cNvPr`\"\n * and had to be. A SmartArt drawing part writes `dsp:cNvPr id=\"0\"` on every\n * shape it contains - PowerPoint generates those parts and regenerates them on\n * any diagram interaction, so whatever the ids there are for, it is not\n * identity. `a23-smartart` is where that turned up.\n */\nexport function v020ShapeIds(ctx: Context): void {\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part)) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n\n const seen = new Map<number, { label: string; branch: XElement[] }[]>();\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'cNvPr' || namespaceOf(element) !== NS.p) continue;\n const raw = attributeValue(element, 'id');\n if (raw === undefined) {\n ctx.add('V020', elementLocation(part, element), '<' + element.qname + '> has no @id.');\n continue;\n }\n const value = integerAttribute(element, 'id');\n if (value === null) {\n ctx.add(\n 'V020',\n attributeLocation(part, element, 'id'),\n '@id=\"' + raw + '\" is not a base-10 unsigned integer.',\n );\n continue;\n }\n // Measured, not read. `ST_DrawingElementId` is `xsd:unsignedInt`, so the\n // schema allows the whole 32-bit range - but 2147483648…4294967294 are\n // whole-package refusals and 4294967295 opens, because PowerPoint reads\n // the attribute as a *signed* 32-bit integer and keeps 0xFFFFFFFF as a\n // sentinel it renumbers away on save. `a39-large-ids` is the deck.\n if (value > SLIDE_ID_MAX && value !== SHEET_ID_MAX) {\n ctx.add(\n 'V020',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is in 2147483648…4294967294, which PowerPoint refuses outright. ST_DrawingElementId ' +\n 'is xsd:unsignedInt and every value up to 2147483647 opens; PowerPoint reads this one ' +\n 'signed. (4294967295 also opens - it is minus one, which PowerPoint keeps as a ' +\n 'sentinel and renumbers away on save.)',\n );\n }\n const branch = branchPath(element);\n const others = seen.get(value) ?? [];\n const clash = others.find((other) => !mutuallyExclusive(other.branch, branch));\n if (clash !== undefined) {\n ctx.add(\n 'V020',\n attributeLocation(part, element, 'id'),\n '@id=' +\n String(value) +\n ' is already used by <' +\n clash.label +\n '> in this part. Shape ids are unique within a part and free to repeat across parts - ' +\n 'renumbering them to be unique across the deck is tidier and detaches every VML ' +\n '@spid and animation target that names the old number.',\n );\n }\n others.push({\n label: element.qname + ' ' + (attributeValue(element, 'name') ?? ''),\n branch,\n });\n seen.set(value, others);\n }\n }\n}\n\n/** A placeholder as the matcher sees it. `null` type means the attribute was absent. */\ninterface Placeholder {\n readonly type: string;\n readonly idx: number;\n readonly element: XElement;\n}\n\n/**\n * `CT_Placeholder` defaults, materialised.\n *\n * `@type` defaults to `body` and `@idx` to `0` in the ECMA-376 schema, and\n * `ctrTitle` normalises to `title` because they are the same slot with\n * different centring. Worth flagging while it is fresh: the plan says\n * `<p:ph/>` means `type=\"obj\"` in sub-phase 2.9 and `type ??= 'body'` in 7.1,\n * and those cannot both be right. The schema says `body`, so that is what this\n * rule uses - and it is one of the reasons the rule is a warning rather than\n * fatal. Sub-phase 7.1 settles it against the 121-case matrix.\n */\nfunction placeholdersOf(root: XElement): Placeholder[] {\n const out: Placeholder[] = [];\n for (const element of descendantElements(root)) {\n if (element.local !== 'ph' || namespaceOf(element) !== NS.p) continue;\n const rawType = attributeValue(element, 'type') ?? 'body';\n const type = rawType === 'ctrTitle' ? 'title' : rawType;\n const idx = Number(attributeValue(element, 'idx') ?? '0');\n out.push({ type, idx: Number.isFinite(idx) ? idx : 0, element });\n }\n return out;\n}\n\n/** Types matched on type alone, ignoring `@idx`. See tier 3. */\nconst TYPE_ONLY = new Set(['sldNum', 'dt', 'ftr', 'hdr']);\n\n/** The five tiers, in order. Returns the matching layout placeholder, or `null`. */\nfunction matchInLayout(slide: Placeholder, layout: readonly Placeholder[]): Placeholder | null {\n const exact = layout.find((ph) => ph.type === slide.type && ph.idx === slide.idx);\n if (exact !== undefined) return exact;\n if (slide.type === 'title') {\n const anyTitle = layout.find((ph) => ph.type === 'title');\n if (anyTitle !== undefined) return anyTitle;\n }\n if (TYPE_ONLY.has(slide.type)) {\n const byType = layout.find((ph) => ph.type === slide.type);\n if (byType !== undefined) return byType;\n }\n if (slide.type === 'body') {\n const bodies = layout.filter((ph) => ph.type === 'body');\n if (bodies.length === 1) return bodies[0]!;\n }\n return null;\n}\n\n/**\n * Every slide placeholder finds a counterpart in its layout.\n *\n * A warning, and the reason matters: PowerPoint opens the file. A `p:ph` that\n * matches nothing inherits nothing - no geometry, no text style, no prompt -\n * and the shape is drawn wherever the renderer can work out, which is a deck\n * that is silently wrong rather than a deck that is refused. Refusing an export\n * over it would block a user from saving a file that already opened fine\n * everywhere, which is the failure mode a validator has to avoid most.\n */\nexport function v021PlaceholderIndices(ctx: Context): void {\n const relsBySource = bySource(readRelsParts(ctx));\n\n for (const part of ctx.parts()) {\n if (ctx.contentType(part) !== CONTENT_TYPE.slide) continue;\n const document = ctx.document(part);\n if (document === null) continue;\n\n const rels = relsBySource.get(normalizePartName(part));\n const layoutRel = (rels?.relationships ?? []).find((rel) => rel.type === REL_TYPE.slideLayout);\n if (layoutRel === undefined) continue; // `V009` has already said so.\n const layoutPart = resolveTarget(rels!.source, layoutRel.target).part;\n if (layoutPart === null) continue;\n const layoutDocument = ctx.document(layoutPart);\n if (layoutDocument === null) continue;\n\n const layout = placeholdersOf(layoutDocument.root);\n for (const slidePh of placeholdersOf(document.root)) {\n if (matchInLayout(slidePh, layout) !== null) continue;\n ctx.add(\n 'V021',\n elementLocation(part, slidePh.element),\n 'placeholder (type=' +\n slidePh.type +\n ', idx=' +\n String(slidePh.idx) +\n ') matches nothing in ' +\n layoutPart +\n ', which offers ' +\n (layout.length === 0\n ? 'none'\n : layout.map((ph) => ph.type + '/' + String(ph.idx)).join(', ')) +\n '. An unmatched placeholder inherits no geometry and no text style.',\n );\n }\n }\n}\n","import { CONTENT_TYPE } from '@pptx-studio/opc';\nimport {\n attribute,\n attributeValue,\n childElements,\n descendantElements,\n namespaceOf,\n NS,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { attributeLocation, elementLocation } from '../report/location.js';\nimport { forEachElement } from './required.js';\n\n/**\n * `V022` … `V026`: schema-legal markup PowerPoint refuses.\n *\n * This is the category that justifies the package. Nothing here can be derived\n * from ECMA-376; every rule is the record of a package built with one change in\n * it, opened, and declined - \"PowerPoint could not open the file\", or\n * `0x80070570`, \"the file or directory is corrupted and unreadable\". No log, no\n * part named, no line number. Sub-phase 1.5's `cli bisect` exists because that\n * is the entire diagnostic channel, and these five rules are what it found\n * before it existed, by hand.\n *\n * Which means each of them is falsifiable in a way the schema rules are not: if\n * a later PowerPoint build opens one of these, the rule is wrong and should be\n * deleted. The `why` in `rules.ts` records what was tried and what opened, so\n * that the person who deletes it knows what they are contradicting.\n */\n\n/** Parts where `hdr` and `sldImg` placeholders are legal - they belong to these families. */\nconst NOTES_FAMILY = new Set<string>([\n CONTENT_TYPE.notesSlide,\n CONTENT_TYPE.notesMaster,\n CONTENT_TYPE.handoutMaster,\n]);\n\n/** `p:ph/@type` is not `hdr` or `sldImg` on a slide, layout or master. */\nexport function v022PlaceholderType(ctx: Context): void {\n for (const part of ctx.parts()) {\n const contentType = ctx.contentType(part);\n if (contentType === undefined || NOTES_FAMILY.has(contentType)) continue;\n if (\n contentType !== CONTENT_TYPE.slide &&\n contentType !== CONTENT_TYPE.slideLayout &&\n contentType !== CONTENT_TYPE.slideMaster\n ) {\n continue;\n }\n const document = ctx.document(part);\n if (document === null) continue;\n\n for (const element of descendantElements(document.root)) {\n if (element.local !== 'ph' || namespaceOf(element) !== NS.p) continue;\n const type = attributeValue(element, 'type');\n if (type !== 'hdr' && type !== 'sldImg') continue;\n ctx.add(\n 'V022',\n attributeLocation(part, element, 'type'),\n 'type=\"' +\n type +\n '\" is a whole-package refusal here, alone and with no other change. The other seven ' +\n 'content types were built as one-type packages in the same bisection and every one ' +\n 'opens: obj, chart, tbl, clipArt, dgm, media, pic. Nothing in the schema says so - ' +\n 'CT_Placeholder is one complex type shared by every sheet family and ' +\n 'ST_PlaceholderType is one enumeration holding all sixteen values - but hdr and ' +\n 'sldImg belong to the notes and handout families and PowerPoint enforces it.',\n );\n }\n }\n}\n\n/**\n * The built-in geometry guides.\n *\n * Deliberately generous, and deliberately temporary. The authoritative table is\n * sub-phase 2.2's - forty-four seeded guides beside the seventeen `fmla`\n * operators - and it belongs in `@pptx-studio/geometry` rather than here. Until\n * it exists this list plus the two shape tests below stand in for it.\n *\n * Generous in the safe direction on purpose. This rule is fatal, so a name we\n * wrongly think is undefined refuses a file that works, while a name we wrongly\n * accept only means we miss one instance of a defect whose real-world form is a\n * typo or a deleted `a:gd` - and neither of those looks anything like `wd12`.\n */\nconst BUILTIN_GUIDES = new Set([\n '3cd4',\n '3cd8',\n '5cd8',\n '7cd8',\n 'b',\n 'cd2',\n 'cd4',\n 'cd8',\n 'h',\n 'hc',\n 'hd2',\n 'hd3',\n 'hd4',\n 'hd5',\n 'hd6',\n 'hd8',\n 'l',\n 'ls',\n 'r',\n 'ss',\n 'ssd2',\n 'ssd4',\n 'ssd6',\n 'ssd8',\n 'ssd16',\n 'ssd32',\n 't',\n 'vc',\n 'w',\n 'wd2',\n 'wd3',\n 'wd4',\n 'wd5',\n 'wd6',\n 'wd8',\n 'wd10',\n 'wd32',\n]);\n\n/** `wd12`, `hd10`, `ssd12` - the same shape as a built-in, with a divisor we did not list. */\nconst BUILTIN_SHAPED = /^(?:w|h|ss|ls)d\\d+$/;\n/** `2cd4`, `5cd8` - a fraction of a full circle. */\nconst ANGLE_SHAPED = /^\\d+cd\\d+$/;\n\n/** A literal number, in EMU or in 60000ths of a degree. Both may be negative. */\nconst LITERAL = /^-?\\d+$/;\n\nfunction isDefinedGuide(name: string, defined: ReadonlySet<string>): boolean {\n if (name === '' || LITERAL.test(name)) return true;\n if (defined.has(name) || BUILTIN_GUIDES.has(name)) return true;\n return BUILTIN_SHAPED.test(name) || ANGLE_SHAPED.test(name);\n}\n\n/** Attributes that hold a guide name rather than a value of their own. */\nconst GUIDE_VALUED: Readonly<Record<string, readonly string[]>> = {\n pt: ['x', 'y'],\n pos: ['x', 'y'],\n rect: ['l', 't', 'r', 'b'],\n ahXY: ['minX', 'maxX', 'minY', 'maxY', 'gdRefX', 'gdRefY'],\n ahPolar: ['minAng', 'maxAng', 'minR', 'maxR', 'gdRefAng', 'gdRefR'],\n cxn: ['ang'],\n arcTo: ['wR', 'hR', 'stAng', 'swAng'],\n};\n\n/**\n * Every geometry guide named is a guide that is defined.\n *\n * Scoped to one `a:custGeom` or `a:prstGeom` at a time, because that is the\n * scope a guide has: `adj1` in one shape has nothing to do with `adj1` in the\n * next. A `prstGeom`'s guides come from the preset definition rather than from\n * the markup, so only its `a:avLst` is checked - which is the whole of what a\n * preset shape can get wrong from here, and is exactly what dragging an adjust\n * handle writes.\n */\nexport function v023GeometryGuides(ctx: Context): void {\n forEachElement(ctx, (part, geometry) => {\n const isCustom = geometry.local === 'custGeom';\n if ((!isCustom && geometry.local !== 'prstGeom') || namespaceOf(geometry) !== NS.a) return;\n\n const defined = new Set<string>();\n for (const element of descendantElements(geometry)) {\n if (element.local !== 'gd') continue;\n const name = attributeValue(element, 'name');\n if (name !== undefined && name !== '') defined.add(name);\n }\n\n for (const element of descendantElements(geometry)) {\n if (element.local === 'gd') {\n // `fmla=\"*/ w adj1 100000\"` - the operator, then two or three\n // arguments, each a guide name or a literal.\n const formula = attributeValue(element, 'fmla');\n if (formula === undefined) continue;\n const args = formula.trim().split(/\\s+/).slice(1);\n for (const arg of args) {\n if (isDefinedGuide(arg, defined)) continue;\n report(ctx, part, element, 'fmla', arg, defined);\n }\n continue;\n }\n const names = GUIDE_VALUED[element.local];\n if (names === undefined || namespaceOf(element) !== NS.a) continue;\n for (const attributeName of names) {\n const value = attribute(element, attributeName);\n if (value === undefined || isDefinedGuide(value.value, defined)) continue;\n report(ctx, part, element, attributeName, value.value, defined);\n }\n }\n });\n}\n\nfunction report(\n ctx: Context,\n part: string,\n element: XElement,\n attributeName: string,\n name: string,\n defined: ReadonlySet<string>,\n): void {\n ctx.add(\n 'V023',\n attributeLocation(part, element, attributeName),\n '\"' +\n name +\n '\" names a guide nothing defines. This geometry defines ' +\n (defined.size === 0 ? 'none' : [...defined].sort().join(', ')) +\n '. ST_GeomGuideName is an unconstrained token, so nothing in the schema forbids it - and ' +\n 'a package containing it is refused outright, not repaired and not drawn without the shape.',\n );\n}\n\n/** The chart namespace, for `V024`. */\nconst CHART_NS = 'http://schemas.openxmlformats.org/drawingml/2006/chart';\n\n/**\n * A series' `c:tx` holds `c:strRef` or `c:v`, and nothing else.\n *\n * Scoped to `c:ser/c:tx` rather than to every `c:tx`, and the distinction is\n * real: a series' text is `CT_SerTx`, a choice of `c:strRef` or `c:v`, while a\n * title's or a data label's `c:tx` is `CT_Tx`, a choice of `c:strRef` or\n * `c:rich`. Checking both with one list would refuse every chart title in the\n * corpus.\n */\nexport function v024SeriesText(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'tx' || namespaceOf(element) !== CHART_NS) return;\n const parent = element.parent;\n if (parent === undefined || parent.local !== 'ser' || namespaceOf(parent) !== CHART_NS) return;\n\n for (const child of childElements(element)) {\n if (child.local === 'strRef' || child.local === 'v') continue;\n ctx.add(\n 'V024',\n elementLocation(part, child),\n '<' +\n child.qname +\n '> inside a series <' +\n element.qname +\n '>. CT_SerTx is a choice of c:strRef or c:v and nothing else. The trap is that c:cat ' +\n 'and c:val, two elements away in the same series, both accept the literal forms - so ' +\n 'a c:strLit here looks like markup that ought to work, and it is a whole-package ' +\n 'refusal.',\n );\n }\n });\n}\n\n/** No `p:control`. */\nexport function v025Control(ctx: Context): void {\n forEachElement(ctx, (part, element) => {\n if (element.local !== 'control' || namespaceOf(element) !== NS.p) return;\n ctx.add(\n 'V025',\n elementLocation(part, element),\n 'a <p:control> is a whole-package refusal in all eight forms tried: bare, name-only, with ' +\n 'and without r:id, with a p:pic preview, with an ActiveX part and its .bin, and inside a ' +\n 'macro-enabled package. An empty <p:controls> is accepted, which places the refusal ' +\n 'precisely on this element.',\n );\n });\n}\n\n/** The chart-style namespace and its thirty-one entries. */\nconst CHART_STYLE_NS = 'http://schemas.microsoft.com/office/drawing/2012/chartStyle';\n\nconst CHART_STYLE_ENTRIES = [\n 'axisTitle',\n 'categoryAxis',\n 'chartArea',\n 'dataLabel',\n 'dataLabelCallout',\n 'dataPoint',\n 'dataPoint3D',\n 'dataPointLine',\n 'dataPointMarker',\n 'dataPointMarkerLayout',\n 'dataPointWireframe',\n 'dataTable',\n 'downBar',\n 'dropLine',\n 'errorBar',\n 'floor',\n 'gridlineMajor',\n 'gridlineMinor',\n 'hiLoLine',\n 'leaderLine',\n 'legend',\n 'plotArea',\n 'plotArea3D',\n 'seriesAxis',\n 'seriesLine',\n 'title',\n 'trendline',\n 'trendlineLabel',\n 'upBar',\n 'valueAxis',\n 'wall',\n] as const;\n\n/**\n * A `cs:chartStyle` carries all thirty-one of its entries.\n *\n * The shape of this finding is the interesting half. A chart with **no**\n * chart-style relationship at all opens; a chart whose style part is present\n * and has four of thirty-one does not. So the rule is not \"the part is\n * required\", it is \"if the part exists it must be complete\" - a subset is worse\n * than an absence, which is the opposite of what any partial-styling model\n * would predict, and is why we found it by shipping four entries rather than by\n * reasoning.\n */\nexport function v026ChartStyleComplete(ctx: Context): void {\n for (const part of ctx.parts()) {\n const document = ctx.document(part);\n if (document === null) continue;\n const root = document.root;\n if (root.local !== 'chartStyle' || namespaceOf(root) !== CHART_STYLE_NS) continue;\n\n const present = new Set(childElements(root).map((child) => child.local));\n const missing = CHART_STYLE_ENTRIES.filter((name) => !present.has(name));\n if (missing.length === 0) continue;\n ctx.add(\n 'V026',\n elementLocation(part, root),\n 'a chart style with ' +\n String(CHART_STYLE_ENTRIES.length - missing.length) +\n ' of its ' +\n String(CHART_STYLE_ENTRIES.length) +\n ' entries. Missing: ' +\n missing.join(', ') +\n '. Four entries were refused and thirty-one opened; a chart with no chart-style ' +\n 'relationship at all is fine.',\n );\n }\n}\n","import { isRelationshipPartName } from '@pptx-studio/opc';\nimport {\n attributeValue,\n descendantElements,\n sourceOf,\n textContent,\n type XDocument,\n type XElement,\n} from '@pptx-studio/xml';\nimport type { Context } from '../context.js';\nimport { elementLocation, partLocation, xpathOf } from '../report/location.js';\n\n/**\n * `V027` … `V029`: what has to come back out unchanged.\n *\n * These are the rules the architecture exists for. Preserving charts, SmartArt,\n * animations, OLE objects and macros is unachievable in any design where the\n * writer has to *understand* a feature in order to emit it - and the moment\n * preservation is a feature rather than the default state, it is a feature with\n * a coverage percentage, and the percentage is never a hundred.\n *\n * So the default is that nothing changes, and these three rules are where that\n * intention becomes falsifiable.\n *\n * ## They need two packages, and they say so when they only have one\n *\n * All three compare against the package as it was opened. Asked to validate a\n * file with no history - `pptx-studio validate deck.pptx`, a deck somebody\n * dropped on a page - there is nothing to compare against and they do not run.\n * The report lists them under `skipped` with that reason, because a\n * preservation rule that reports nothing because it had nothing to compare\n * against looks exactly like one that found nothing, and those are opposite\n * answers.\n */\n\n/** `ppt/embeddings/…` - OLE2/CFB compound files. Never ours to rewrite. */\nfunction isEmbedding(part: string): boolean {\n return /^\\/ppt\\/embeddings\\//i.test(part);\n}\n\n/**\n * A part nobody edited comes back out byte for byte.\n *\n * \"Nobody edited\" is `PartInfo.fromArchive`, the store's own record of whether a\n * part's bytes still come from the archive it was opened from - not a byte\n * comparison, which could not tell an edit that happened to produce identical\n * bytes from no edit at all. The rule then checks the converse: a part the store\n * says is untouched really is identical.\n *\n * That is not circular, because the two facts come from different places. The\n * flag is set by whoever called `replacePart`; the bytes come from whatever the\n * writer actually emitted. A writer that re-serialised a clean part - the exact\n * failure this rule exists for - would leave the flag alone and change the\n * bytes, and this is where the two stop agreeing.\n */\nexport function v027UneditedPartsUnchanged(ctx: Context): void {\n const baseline = ctx.baseline;\n if (baseline === null) return;\n\n for (const part of ctx.parts()) {\n const before = ctx.baselineRead(part);\n if (before === null) continue; // Added this session. Nothing to preserve.\n\n const embedding = isEmbedding(part);\n if (embedding && ctx.edited(part)) {\n ctx.add(\n 'V027',\n partLocation(part),\n 'an OLE embedding was replaced. ppt/embeddings/*.bin are OLE2/CFB compound files and any ' +\n 'rewrite of one is a guaranteed repair prompt - we render their preview and never ' +\n 'touch the object.',\n );\n continue;\n }\n if (!embedding && ctx.edited(part)) continue; // Edited on purpose.\n\n const after = ctx.read(part);\n if (after === null) continue;\n if (sameBytes(before, after)) continue;\n\n ctx.add(\n 'V027',\n partLocation(part),\n 'nobody edited this part and its bytes changed anyway (' +\n String(before.byteLength) +\n ' bytes in, ' +\n String(after.byteLength) +\n ' out). A part that was not edited is streamed through, never re-serialised: the ' +\n 'moment that stops being true, every feature we cannot parse is a feature we can lose.',\n );\n }\n}\n\nfunction sameBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.byteLength !== b.byteLength) return false;\n for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** The containers held opaque, found by local name so that vocabularies never read are covered too. */\nfunction isOpaqueContainer(element: XElement): boolean {\n // An extension is an `ext` inside an `extLst`; the extent inside `a:xfrm` is spelled `ext` as well.\n return (\n element.local === 'AlternateContent' ||\n (element.local === 'ext' && element.parent?.local === 'extLst')\n );\n}\n\n/** Every opaque container in a document, as its exact source text. */\nfunction opaqueSources(document: XDocument): { element: XElement; source: string }[] {\n const out: { element: XElement; source: string }[] = [];\n for (const element of descendantElements(document.root)) {\n if (!isOpaqueContainer(element)) continue;\n out.push({ element, source: sourceOf(document, element) });\n }\n return out;\n}\n\n/**\n * No `mc:AlternateContent` branch and no extension was rebuilt.\n *\n * The check is a multiset test, not a positional one: every opaque container in\n * the part we are about to write must appear, character for character,\n * somewhere in the part as it was opened. That formulation is deliberate.\n *\n * A positional comparison - same XPath, same text - would be exact and would\n * also fire every time a shape was inserted above one, because the index in the\n * path shifts. The multiset test cannot be fooled in the direction that matters\n * (text nobody wrote before is text we wrote) and is immune to the reordering\n * that is a normal, permitted edit.\n *\n * **Deletion is not this rule's business.** An extension can leave because the\n * shape holding it was deleted, and that is a document operation the user asked\n * for. What must never happen is markup *appearing* here that we composed:\n * `mc:Choice/@Requires` names a prefix rather than a URI, so a rewritten branch\n * is how ignorable extension markup becomes a hard error - and `a34-extlst`\n * measured that PowerPoint carries an unknown `a:ext/@uri` through untouched,\n * so an extension we rebuild is one the file would otherwise have kept for ever.\n */\nexport function v028OpaqueContainersUnchanged(ctx: Context): void {\n if (ctx.baseline === null) return;\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part) || !ctx.edited(part)) continue;\n const after = ctx.document(part);\n const before = ctx.baselineDocument(part);\n if (after === null || before === null) continue;\n\n const known = new Set(opaqueSources(before).map((entry) => entry.source));\n for (const entry of opaqueSources(after)) {\n if (known.has(entry.source)) continue;\n const uri = attributeValue(entry.element, 'uri');\n ctx.add(\n 'V028',\n elementLocation(part, entry.element),\n '<' +\n entry.element.qname +\n '>' +\n (uri === undefined ? '' : ' uri=\"' + uri + '\"') +\n ' is not markup this part arrived with. These containers are carried through ' +\n 'byte for byte and never composed: we do not know what is in them, which is the ' +\n 'whole reason they are held opaque.',\n );\n }\n }\n}\n\n/** An `a:fld` and the two things about it that must survive. */\ninterface Field {\n readonly id: string;\n readonly text: string;\n readonly element: XElement;\n}\n\nfunction fieldsOf(root: XElement): Field[] {\n const out: Field[] = [];\n for (const element of descendantElements(root)) {\n if (element.local !== 'fld') continue;\n out.push({\n id: attributeValue(element, 'id') ?? '',\n text: textContent(element),\n element,\n });\n }\n return out;\n}\n\n/** `a:t` elements whose `xml:space` was declared, keyed by path. */\nfunction spacePreserved(root: XElement): Map<string, XElement> {\n const out = new Map<string, XElement>();\n for (const element of descendantElements(root)) {\n if (element.local !== 't') continue;\n if (attributeValue(element, 'xml:space') !== 'preserve') continue;\n out.set(xpathOf(element), element);\n }\n return out;\n}\n\n/** The path of every `a:t`, so \"is this one still there\" is a set lookup. */\nfunction textPaths(root: XElement): Set<string> {\n const out = new Set<string>();\n for (const element of descendantElements(root)) {\n if (element.local === 't') out.add(xpathOf(element));\n }\n return out;\n}\n\n/**\n * Text and field identity survive an edit.\n *\n * Three small, separately silent losses.\n *\n * **`xml:space=\"preserve\"` is preserved, not required.** The distinction is\n * measured: 120 `<a:t>` elements in the corpus carry leading or trailing\n * whitespace *without* the attribute and PowerPoint round-trips every one of\n * them with the whitespace intact, so a rule that demanded the attribute would\n * fire on real files that work. What is not allowed is dropping one that was\n * there, because then the attribute's absence starts meaning something it did\n * not mean before.\n *\n * **`a:fld/@id` is a required `ST_Guid`** identifying the field across saves.\n * Regenerating one can make PowerPoint repair the file, and a repair is the one\n * outcome this whole package exists to prevent.\n *\n * **A field's cached `a:t` is its only rendering** anywhere we cannot evaluate\n * the field ourselves. Discarding it turns a date placeholder into an empty box\n * on every consumer that is not PowerPoint - including, for anything we have\n * not implemented, us.\n */\nexport function v029TextAndFieldIdentity(ctx: Context): void {\n if (ctx.baseline === null) return;\n\n for (const part of ctx.parts()) {\n if (isRelationshipPartName(part) || !ctx.edited(part)) continue;\n const after = ctx.document(part);\n const before = ctx.baselineDocument(part);\n if (after === null || before === null) continue;\n\n // xml:space, by path. A path that no longer exists is a deletion and not\n // this rule's business; a path that still exists and has lost the attribute\n // is a rewrite that changed what the text means.\n //\n // Both sets are built once. The obvious shape - scan the new document for\n // each old path - is quadratic in the number of `<a:t>` elements, and a\n // slide with a thousand runs is an ordinary slide.\n const afterSpace = spacePreserved(after.root);\n const afterPaths = textPaths(after.root);\n for (const [path, element] of spacePreserved(before.root)) {\n if (afterSpace.has(path)) continue;\n if (!afterPaths.has(path)) continue;\n ctx.add(\n 'V029',\n { part, xpath: path, offset: element.start },\n 'this <' +\n element.qname +\n '> arrived with xml:space=\"preserve\" and no longer has it. The attribute is not ' +\n 'required - 120 elements in our corpus carry edge whitespace without it - but dropping ' +\n 'one that was written changes what the text is.',\n );\n }\n\n const afterFields = fieldsOf(after.root);\n const beforeById = new Map(fieldsOf(before.root).map((field) => [field.id, field]));\n const beforeIds = new Set(beforeById.keys());\n\n for (const field of afterFields) {\n if (beforeIds.has(field.id)) {\n const original = beforeById.get(field.id)!;\n if (original.text !== '' && field.text.trim() === '') {\n ctx.add(\n 'V029',\n elementLocation(part, field.element),\n 'field ' +\n field.id +\n ' has lost its cached text (\"' +\n original.text +\n '\"). The cache is what renders anywhere the field cannot be evaluated, which ' +\n 'includes every consumer that is not PowerPoint.',\n );\n }\n continue;\n }\n ctx.add(\n 'V029',\n elementLocation(part, field.element),\n 'field id=\"' +\n field.id +\n '\" is not one this part arrived with. a:fld/@id is a required ST_Guid identifying the ' +\n 'field across saves; regenerating one can make PowerPoint repair the file. The ids ' +\n 'that were here: ' +\n (beforeIds.size === 0 ? 'none' : [...beforeIds].join(', ')) +\n '.',\n );\n }\n }\n}\n","import { PartStore, readZip, type ReadZipOptions, type ZipArchive } from '@pptx-studio/opc';\nimport { createContext, type Context, type RuntimeContext } from './context.js';\nimport { ValidateError } from './errors.js';\nimport {\n v001ContentTypeCoverage,\n v002ContentTypeMap,\n v003ArchiveShape,\n v004PartNames,\n v005MainPart,\n} from './rules/package.js';\nimport {\n v006ReferencesResolve,\n v007RelationshipIds,\n v008TargetsResolve,\n v009RequiredEdges,\n} from './rules/relationships.js';\nimport { v010SchemaOrder, v011ExtLstLast, v012UnexpectedChild } from './rules/order.js';\nimport {\n v013NotesSize,\n v014ColorMap,\n v015ShapeTreePrologue,\n v016TextBody,\n v017GraphicFrame,\n} from './rules/required.js';\nimport { v018SlideIds, v019SheetIds, v020ShapeIds, v021PlaceholderIndices } from './rules/id.js';\nimport {\n v022PlaceholderType,\n v023GeometryGuides,\n v024SeriesText,\n v025Control,\n v026ChartStyleComplete,\n} from './rules/refusal.js';\nimport {\n v027UneditedPartsUnchanged,\n v028OpaqueContainersUnchanged,\n v029TextAndFieldIdentity,\n} from './rules/preservation.js';\nimport {\n buildReport,\n findingKey,\n type Finding,\n type Report,\n type SkippedRule,\n} from './report/report.js';\nimport { ruleById, RULE_IDS, type RuleId } from './rules/rules.js';\n\n/**\n * The twenty-nine, wired to their implementations.\n *\n * A plain table, so that \"is every rule reachable\" is a thing a test can ask\n * rather than a thing a reader has to believe. `rules.test.ts` asserts that the\n * keys here are exactly `RULE_IDS` - a rule with a definition and no function\n * would otherwise sit in the table looking enforced.\n */\nconst IMPLEMENTATIONS: Readonly<Record<RuleId, (ctx: Context) => void>> = {\n V001: v001ContentTypeCoverage,\n V002: v002ContentTypeMap,\n V003: v003ArchiveShape,\n V004: v004PartNames,\n V005: v005MainPart,\n V006: v006ReferencesResolve,\n V007: v007RelationshipIds,\n V008: v008TargetsResolve,\n V009: v009RequiredEdges,\n V010: v010SchemaOrder,\n V011: v011ExtLstLast,\n V012: v012UnexpectedChild,\n V013: v013NotesSize,\n V014: v014ColorMap,\n V015: v015ShapeTreePrologue,\n V016: v016TextBody,\n V017: v017GraphicFrame,\n V018: v018SlideIds,\n V019: v019SheetIds,\n V020: v020ShapeIds,\n V021: v021PlaceholderIndices,\n V022: v022PlaceholderType,\n V023: v023GeometryGuides,\n V024: v024SeriesText,\n V025: v025Control,\n V026: v026ChartStyleComplete,\n V027: v027UneditedPartsUnchanged,\n V028: v028OpaqueContainersUnchanged,\n V029: v029TextAndFieldIdentity,\n};\n\n/** Rules that cannot run without the archive bytes. See `Context.archive`. */\nconst ARCHIVE_RULES: readonly RuleId[] = ['V003'];\n\nexport interface ValidateOptions {\n /**\n * The package about to be handed over.\n *\n * On an export this is the store the writer emitted from, **not** a store\n * re-opened from the written bytes. The difference is `V027`: a re-opened\n * store thinks every part came from the archive, so the one rule that asks\n * \"did anything change that nobody edited\" would have no history to ask\n * about and would answer yes about every deliberate edit.\n */\n readonly store?: PartStore;\n /**\n * The archive, when the caller has it.\n *\n * Required for `V003` and for the duplicate half of `V002` - a duplicate\n * `<Default>` is visible only in the markup, because the parsed content-type\n * map collapses one that agrees with itself. Given a `store` and no `bytes`,\n * those are skipped and the report says so.\n */\n readonly bytes?: Uint8Array;\n /** The package as it was opened. The six preservation rules need it. */\n readonly baseline?: PartStore;\n /** The baseline's archive, so an inherited `V003` can be recognised as inherited. */\n readonly baselineBytes?: Uint8Array;\n /** A subset to run. Defaults to all twenty-nine. */\n readonly rules?: readonly RuleId[];\n /** Passed to `readZip` when `bytes` are given. */\n readonly zip?: ReadZipOptions;\n}\n\nfunction openArchive(\n bytes: Uint8Array | undefined,\n zip: ReadZipOptions | undefined,\n): ZipArchive | null {\n if (bytes === undefined) return null;\n try {\n return readZip(bytes, zip ?? {});\n } catch {\n // The store below will fail on the same bytes and say so with a code. A\n // second, worse-worded copy of that message helps nobody.\n return null;\n }\n}\n\n/**\n * Check a package against the rules.\n *\n * Never throws for anything it finds - a broken package produces a report with\n * findings in it, which is the shape a caller can render. It throws only when\n * it was handed something it cannot open at all.\n */\nexport function validatePackage(options: ValidateOptions): Report {\n const archive = openArchive(options.bytes, options.zip);\n const store = options.store ?? openStore(options);\n\n const requested = resolveRules(options.rules);\n const skipped: SkippedRule[] = [];\n const running: RuleId[] = [];\n\n for (const id of requested) {\n const rule = ruleById(id)!;\n if (rule.needsBaseline === true && options.baseline === undefined) {\n skipped.push({\n rule: id,\n why:\n 'it compares against the package as it was opened, and none was supplied. ' +\n 'A preservation rule with nothing to compare against reports nothing, which looks ' +\n 'exactly like finding nothing.',\n });\n continue;\n }\n if (ARCHIVE_RULES.includes(id) && archive === null) {\n skipped.push({\n rule: id,\n why: 'it reads the archive itself, and only a PartStore was supplied.',\n });\n continue;\n }\n running.push(id);\n }\n\n const ctx = createContext({\n store,\n bytes: options.bytes ?? null,\n archive,\n baseline: options.baseline ?? null,\n });\n run(ctx, running);\n\n const findings = attributeOrigins(ctx, options, running);\n\n return buildReport({\n findings,\n checked: running,\n skipped,\n problems: ctx.problems,\n });\n}\n\nfunction openStore(options: ValidateOptions): PartStore {\n if (options.bytes === undefined) {\n throw new ValidateError(\n 'ERR_UNVALIDATABLE',\n 'validatePackage needs either a `store` or the archive `bytes`; it was given neither.',\n );\n }\n try {\n return PartStore.open(options.bytes, options.zip);\n } catch (error) {\n throw new ValidateError(\n 'ERR_UNVALIDATABLE',\n 'the package could not be opened, so there is nothing to validate: ' +\n (error instanceof Error ? error.message : String(error)),\n );\n }\n}\n\nfunction resolveRules(requested: readonly RuleId[] | undefined): readonly RuleId[] {\n if (requested === undefined) return RULE_IDS;\n for (const id of requested) {\n if (ruleById(id) === undefined) {\n throw new ValidateError('ERR_UNKNOWN_RULE', 'there is no rule ' + id, { rule: id });\n }\n }\n // Run in table order whatever order the caller asked in, so a report reads\n // the same way however it was produced.\n return RULE_IDS.filter((id) => requested.includes(id));\n}\n\nfunction run(ctx: RuntimeContext, rules: readonly RuleId[]): void {\n for (const id of rules) IMPLEMENTATIONS[id](ctx);\n}\n\n/**\n * Decide, for each finding, whether we introduced it.\n *\n * The second pass is the whole of it: run the same rules against the package as\n * it was opened and difference the two sets. A finding in both was already\n * there. See `report.ts` for why that question is the one that decides whether\n * an export is refused, and why answering it by differencing beats answering it\n * per rule.\n *\n * Three properties make it cheap enough to be unconditional in the only case\n * that matters. It runs **only when something fatal was found**, so a clean\n * export - which is nearly all of them - pays nothing. It runs **only the rules\n * that fired**, not all twenty-nine. And it skips the preservation rules, which\n * would be comparing the baseline against itself and would find nothing by\n * construction.\n */\nfunction attributeOrigins(\n ctx: RuntimeContext,\n options: ValidateOptions,\n running: readonly RuleId[],\n): readonly Finding[] {\n const baseline = options.baseline;\n if (baseline === undefined) return ctx.findings;\n\n const fatal = ctx.findings.filter((finding) => finding.severity === 'fatal');\n if (fatal.length === 0) {\n return ctx.findings.map((finding) => ({ ...finding, origin: 'introduced' as const }));\n }\n\n const firedRules = new Set(fatal.map((finding) => finding.rule));\n const replay = running.filter((id) => firedRules.has(id) && ruleById(id)!.needsBaseline !== true);\n\n const before = createContext({\n store: baseline,\n bytes: options.baselineBytes ?? null,\n archive: openArchive(options.baselineBytes, options.zip),\n baseline: null,\n });\n run(before, replay);\n const inherited = new Set(before.findings.map(findingKey));\n\n return ctx.findings.map((finding) => ({\n ...finding,\n origin: inherited.has(findingKey(finding)) ? ('inherited' as const) : ('introduced' as const),\n }));\n}\n\n/**\n * Validate, and refuse to go on if we broke something.\n *\n * The one call an export path makes. It throws rather than returning a boolean\n * because the failure has to be impossible to ignore: PowerPoint emits no\n * diagnostic log, its refusal message names no part and no line, and a user who\n * gets a repair prompt has no way at all to find out why. This is the only\n * feedback loop that exists, and a caller who forgot to check a return value\n * would have removed it.\n */\nexport function assertValid(options: ValidateOptions): Report {\n const report = validatePackage(options);\n if (report.ok) return report;\n const blocking = report.findings.filter(\n (finding) => finding.severity === 'fatal' && finding.origin !== 'inherited',\n );\n throw new ValidateError(\n 'ERR_VALIDATION_FAILED',\n 'refusing to hand over the package: ' +\n String(report.blocking) +\n ' fatal finding(s) this session introduced. First: ' +\n blocking[0]!.rule +\n ' at ' +\n blocking[0]!.where.part +\n (blocking[0]!.where.xpath === null ? '' : ' ' + blocking[0]!.where.xpath) +\n ' - ' +\n blocking[0]!.message,\n { part: blocking[0]!.where.part, report },\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED