@deckflow/deckuse 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +342 -0
- package/README.fr.md +342 -0
- package/README.ja.md +342 -0
- package/README.ko.md +342 -0
- package/README.md +46 -8
- package/README.pt-BR.md +342 -0
- package/README.ru.md +342 -0
- package/README.zh-CN.md +367 -0
- package/assets/default.docx +0 -0
- package/assets/default.pptx +0 -0
- package/dist/bin.js +183 -19
- package/dist/bin.js.map +1 -1
- package/dist/core/adapter.d.ts +24 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +20 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/executor.d.ts +24 -0
- package/dist/core/executor.d.ts.map +1 -0
- package/dist/core/executor.js +65 -0
- package/dist/core/executor.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/length.d.ts +27 -0
- package/dist/core/length.d.ts.map +1 -0
- package/dist/core/length.js +63 -0
- package/dist/core/length.js.map +1 -0
- package/dist/core/measure.d.ts +24 -0
- package/dist/core/measure.d.ts.map +1 -0
- package/dist/core/measure.js +79 -0
- package/dist/core/measure.js.map +1 -0
- package/dist/core/not-implemented.d.ts +3 -0
- package/dist/core/not-implemented.d.ts.map +1 -0
- package/dist/core/not-implemented.js +12 -0
- package/dist/core/not-implemented.js.map +1 -0
- package/dist/core/schema.d.ts +3035 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +798 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/default-template.d.ts +8 -0
- package/dist/default-template.d.ts.map +1 -0
- package/dist/default-template.js +29 -0
- package/dist/default-template.js.map +1 -0
- package/dist/docx/adapter.d.ts +29 -0
- package/dist/docx/adapter.d.ts.map +1 -0
- package/dist/docx/adapter.js +442 -0
- package/dist/docx/adapter.js.map +1 -0
- package/dist/docx/addressing.d.ts +18 -0
- package/dist/docx/addressing.d.ts.map +1 -0
- package/dist/docx/addressing.js +111 -0
- package/dist/docx/addressing.js.map +1 -0
- package/dist/docx/blank.d.ts +4 -0
- package/dist/docx/blank.d.ts.map +1 -0
- package/dist/docx/blank.js +75 -0
- package/dist/docx/blank.js.map +1 -0
- package/dist/docx/index-sync.d.ts +7 -0
- package/dist/docx/index-sync.d.ts.map +1 -0
- package/dist/docx/index-sync.js +24 -0
- package/dist/docx/index-sync.js.map +1 -0
- package/dist/docx/index.d.ts +5 -0
- package/dist/docx/index.d.ts.map +1 -0
- package/dist/docx/index.js +4 -0
- package/dist/docx/index.js.map +1 -0
- package/dist/docx/indexer.d.ts +41 -0
- package/dist/docx/indexer.d.ts.map +1 -0
- package/dist/docx/indexer.js +353 -0
- package/dist/docx/indexer.js.map +1 -0
- package/dist/docx/mutations.d.ts +5 -0
- package/dist/docx/mutations.d.ts.map +1 -0
- package/dist/docx/mutations.js +311 -0
- package/dist/docx/mutations.js.map +1 -0
- package/dist/docx/paragraphs.d.ts +26 -0
- package/dist/docx/paragraphs.d.ts.map +1 -0
- package/dist/docx/paragraphs.js +314 -0
- package/dist/docx/paragraphs.js.map +1 -0
- package/dist/docx/properties.d.ts +23 -0
- package/dist/docx/properties.d.ts.map +1 -0
- package/dist/docx/properties.js +414 -0
- package/dist/docx/properties.js.map +1 -0
- package/dist/docx/tables.d.ts +4 -0
- package/dist/docx/tables.d.ts.map +1 -0
- package/dist/docx/tables.js +64 -0
- package/dist/docx/tables.js.map +1 -0
- package/dist/docx/text-spans.d.ts +25 -0
- package/dist/docx/text-spans.d.ts.map +1 -0
- package/dist/docx/text-spans.js +142 -0
- package/dist/docx/text-spans.js.map +1 -0
- package/dist/docx/types.d.ts +27 -0
- package/dist/docx/types.d.ts.map +1 -0
- package/dist/docx/types.js +2 -0
- package/dist/docx/types.js.map +1 -0
- package/dist/docx/workspace.d.ts +20 -0
- package/dist/docx/workspace.d.ts.map +1 -0
- package/dist/docx/workspace.js +145 -0
- package/dist/docx/workspace.js.map +1 -0
- package/dist/docx/xml.d.ts +18 -0
- package/dist/docx/xml.d.ts.map +1 -0
- package/dist/docx/xml.js +87 -0
- package/dist/docx/xml.js.map +1 -0
- package/dist/edition-config/index.d.ts +25 -0
- package/dist/edition-config/index.d.ts.map +1 -0
- package/dist/edition-config/index.js +22 -0
- package/dist/edition-config/index.js.map +1 -0
- package/dist/edition.d.ts +2 -2
- package/dist/edition.d.ts.map +1 -1
- package/dist/edition.js +1 -1
- package/dist/edition.js.map +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +124 -32
- package/dist/help.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/key/index.d.ts +2 -0
- package/dist/key/index.d.ts.map +1 -0
- package/dist/key/index.js +3 -0
- package/dist/key/index.js.map +1 -0
- package/dist/monitor-daemon.d.ts +21 -8
- package/dist/monitor-daemon.d.ts.map +1 -1
- package/dist/monitor-daemon.js +189 -51
- package/dist/monitor-daemon.js.map +1 -1
- package/dist/monitor-registry.d.ts +34 -0
- package/dist/monitor-registry.d.ts.map +1 -0
- package/dist/monitor-registry.js +191 -0
- package/dist/monitor-registry.js.map +1 -0
- package/dist/monitor.js +1 -1
- package/dist/monitor.js.map +1 -1
- package/dist/numbers/index.d.ts +2 -0
- package/dist/numbers/index.d.ts.map +1 -0
- package/dist/numbers/index.js +3 -0
- package/dist/numbers/index.js.map +1 -0
- package/dist/opc/index.d.ts +90 -0
- package/dist/opc/index.d.ts.map +1 -0
- package/dist/opc/index.js +569 -0
- package/dist/opc/index.js.map +1 -0
- package/dist/pptx/adapter.d.ts +167 -0
- package/dist/pptx/adapter.d.ts.map +1 -0
- package/dist/pptx/adapter.js +807 -0
- package/dist/pptx/adapter.js.map +1 -0
- package/dist/pptx/addressing.d.ts +45 -0
- package/dist/pptx/addressing.d.ts.map +1 -0
- package/dist/pptx/addressing.js +428 -0
- package/dist/pptx/addressing.js.map +1 -0
- package/dist/pptx/align.d.ts +24 -0
- package/dist/pptx/align.d.ts.map +1 -0
- package/dist/pptx/align.js +112 -0
- package/dist/pptx/align.js.map +1 -0
- package/dist/pptx/chart-classify.d.ts +10 -0
- package/dist/pptx/chart-classify.d.ts.map +1 -0
- package/dist/pptx/chart-classify.js +58 -0
- package/dist/pptx/chart-classify.js.map +1 -0
- package/dist/pptx/chart.d.ts +42 -0
- package/dist/pptx/chart.d.ts.map +1 -0
- package/dist/pptx/chart.js +614 -0
- package/dist/pptx/chart.js.map +1 -0
- package/dist/pptx/edition-extension.d.ts +25 -0
- package/dist/pptx/edition-extension.d.ts.map +1 -0
- package/dist/pptx/edition-extension.js +10 -0
- package/dist/pptx/edition-extension.js.map +1 -0
- package/dist/pptx/edition.d.ts +20 -0
- package/dist/pptx/edition.d.ts.map +1 -0
- package/dist/pptx/edition.js +69 -0
- package/dist/pptx/edition.js.map +1 -0
- package/dist/pptx/elements.d.ts +12 -0
- package/dist/pptx/elements.d.ts.map +1 -0
- package/dist/pptx/elements.js +224 -0
- package/dist/pptx/elements.js.map +1 -0
- package/dist/pptx/hyperlink.d.ts +7 -0
- package/dist/pptx/hyperlink.d.ts.map +1 -0
- package/dist/pptx/hyperlink.js +81 -0
- package/dist/pptx/hyperlink.js.map +1 -0
- package/dist/pptx/index-sync.d.ts +7 -0
- package/dist/pptx/index-sync.d.ts.map +1 -0
- package/dist/pptx/index-sync.js +24 -0
- package/dist/pptx/index-sync.js.map +1 -0
- package/dist/pptx/index.d.ts +10 -0
- package/dist/pptx/index.d.ts.map +1 -0
- package/dist/pptx/index.js +7 -0
- package/dist/pptx/index.js.map +1 -0
- package/dist/pptx/indexer.d.ts +19 -0
- package/dist/pptx/indexer.d.ts.map +1 -0
- package/dist/pptx/indexer.js +319 -0
- package/dist/pptx/indexer.js.map +1 -0
- package/dist/pptx/layout-ref.d.ts +41 -0
- package/dist/pptx/layout-ref.d.ts.map +1 -0
- package/dist/pptx/layout-ref.js +145 -0
- package/dist/pptx/layout-ref.js.map +1 -0
- package/dist/pptx/media.d.ts +15 -0
- package/dist/pptx/media.d.ts.map +1 -0
- package/dist/pptx/media.js +145 -0
- package/dist/pptx/media.js.map +1 -0
- package/dist/pptx/mutations.d.ts +11 -0
- package/dist/pptx/mutations.d.ts.map +1 -0
- package/dist/pptx/mutations.js +1111 -0
- package/dist/pptx/mutations.js.map +1 -0
- package/dist/pptx/picture.d.ts +25 -0
- package/dist/pptx/picture.d.ts.map +1 -0
- package/dist/pptx/picture.js +118 -0
- package/dist/pptx/picture.js.map +1 -0
- package/dist/pptx/placeholder-role.d.ts +19 -0
- package/dist/pptx/placeholder-role.d.ts.map +1 -0
- package/dist/pptx/placeholder-role.js +71 -0
- package/dist/pptx/placeholder-role.js.map +1 -0
- package/dist/pptx/properties.d.ts +13 -0
- package/dist/pptx/properties.d.ts.map +1 -0
- package/dist/pptx/properties.js +587 -0
- package/dist/pptx/properties.js.map +1 -0
- package/dist/pptx/resolve-properties.d.ts +17 -0
- package/dist/pptx/resolve-properties.d.ts.map +1 -0
- package/dist/pptx/resolve-properties.js +571 -0
- package/dist/pptx/resolve-properties.js.map +1 -0
- package/dist/pptx/slide-size.d.ts +9 -0
- package/dist/pptx/slide-size.d.ts.map +1 -0
- package/dist/pptx/slide-size.js +29 -0
- package/dist/pptx/slide-size.js.map +1 -0
- package/dist/pptx/slides.d.ts +15 -0
- package/dist/pptx/slides.d.ts.map +1 -0
- package/dist/pptx/slides.js +236 -0
- package/dist/pptx/slides.js.map +1 -0
- package/dist/pptx/table-measure.d.ts +43 -0
- package/dist/pptx/table-measure.d.ts.map +1 -0
- package/dist/pptx/table-measure.js +70 -0
- package/dist/pptx/table-measure.js.map +1 -0
- package/dist/pptx/table.d.ts +23 -0
- package/dist/pptx/table.d.ts.map +1 -0
- package/dist/pptx/table.js +529 -0
- package/dist/pptx/table.js.map +1 -0
- package/dist/pptx/types.d.ts +27 -0
- package/dist/pptx/types.d.ts.map +1 -0
- package/dist/pptx/types.js +2 -0
- package/dist/pptx/types.js.map +1 -0
- package/dist/pptx/workspace.d.ts +23 -0
- package/dist/pptx/workspace.d.ts.map +1 -0
- package/dist/pptx/workspace.js +148 -0
- package/dist/pptx/workspace.js.map +1 -0
- package/dist/pptx/xml.d.ts +67 -0
- package/dist/pptx/xml.d.ts.map +1 -0
- package/dist/pptx/xml.js +355 -0
- package/dist/pptx/xml.js.map +1 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +14 -2
- package/dist/render.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace/git.d.ts +7 -0
- package/dist/workspace/git.d.ts.map +1 -0
- package/dist/workspace/git.js +82 -0
- package/dist/workspace/git.js.map +1 -0
- package/dist/workspace/index.d.ts +7 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +7 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/lock.d.ts +3 -0
- package/dist/workspace/lock.d.ts.map +1 -0
- package/dist/workspace/lock.js +35 -0
- package/dist/workspace/lock.js.map +1 -0
- package/dist/workspace/metadata.d.ts +4 -0
- package/dist/workspace/metadata.d.ts.map +1 -0
- package/dist/workspace/metadata.js +21 -0
- package/dist/workspace/metadata.js.map +1 -0
- package/dist/workspace/operations.d.ts +14 -0
- package/dist/workspace/operations.d.ts.map +1 -0
- package/dist/workspace/operations.js +35 -0
- package/dist/workspace/operations.js.map +1 -0
- package/dist/workspace/paths.d.ts +11 -0
- package/dist/workspace/paths.d.ts.map +1 -0
- package/dist/workspace/paths.js +12 -0
- package/dist/workspace/paths.js.map +1 -0
- package/dist/workspace/revision.d.ts +6 -0
- package/dist/workspace/revision.d.ts.map +1 -0
- package/dist/workspace/revision.js +15 -0
- package/dist/workspace/revision.js.map +1 -0
- package/dist/xlsx/index.d.ts +2 -0
- package/dist/xlsx/index.d.ts.map +1 -0
- package/dist/xlsx/index.js +3 -0
- package/dist/xlsx/index.js.map +1 -0
- package/package.json +48 -27
- package/schema/command.schema.json +2399 -0
- package/dist/.tsbuildinfo +0 -1
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
import { copyFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { err, ok, } from '../core/index.js';
|
|
4
|
+
import { OpcArchive } from '../opc/index.js';
|
|
5
|
+
import { isIntegerRevision, nextRevision } from '../workspace/index.js';
|
|
6
|
+
import { cNvPrIdOf, resolveTarget, targetPathForItem, uidForItem } from './addressing.js';
|
|
7
|
+
import { editionCapabilities, editionMetadata } from './edition.js';
|
|
8
|
+
import { buildIndex, findIndexed, matchesSelector, mergeSlides } from './indexer.js';
|
|
9
|
+
import { loadIndex } from './index-sync.js';
|
|
10
|
+
import { layoutDisplayName, layoutListMeta, orderedLayouts, slideLayoutPart, } from './layout-ref.js';
|
|
11
|
+
import { mutate } from './mutations.js';
|
|
12
|
+
import { resolveProperties } from './resolve-properties.js';
|
|
13
|
+
import { syncAppSlideCounts } from './slides.js';
|
|
14
|
+
import { initializeWorkspace, isPackageStale, packagePath, persistWrite, readHistory, readManifest, repackWorkspace, revision, sourceDir, undoWrites, withWriteLock, } from './workspace.js';
|
|
15
|
+
import { NS, descendants } from './xml.js';
|
|
16
|
+
const VERSION = '0.5.0';
|
|
17
|
+
const WRITE_TYPES = new Set([
|
|
18
|
+
'setText',
|
|
19
|
+
'replaceText',
|
|
20
|
+
'setTransform',
|
|
21
|
+
'setProperties',
|
|
22
|
+
'set',
|
|
23
|
+
'xfrmSet',
|
|
24
|
+
'setTableLayout',
|
|
25
|
+
'zMove',
|
|
26
|
+
'alignElements',
|
|
27
|
+
'add',
|
|
28
|
+
'addSlide',
|
|
29
|
+
'setSlideLayout',
|
|
30
|
+
'addShape',
|
|
31
|
+
'remove',
|
|
32
|
+
'replacePicture',
|
|
33
|
+
'duplicate',
|
|
34
|
+
'batch',
|
|
35
|
+
'applyTransaction',
|
|
36
|
+
]);
|
|
37
|
+
export const pptxCapabilities = {
|
|
38
|
+
protocol: '2.0',
|
|
39
|
+
...editionMetadata,
|
|
40
|
+
slides: { add: true, duplicate: true, remove: true, setLayout: true },
|
|
41
|
+
// Master/layout/theme: list always. `edit` flags are status metadata only —
|
|
42
|
+
// writes require a registered PptxEditionExtension (never opened by flags alone).
|
|
43
|
+
masters: { list: true, edit: editionCapabilities.mastersEdit },
|
|
44
|
+
layouts: { list: true, edit: editionCapabilities.layoutsEdit },
|
|
45
|
+
theme: { list: true, edit: editionCapabilities.themeEdit },
|
|
46
|
+
elements: [
|
|
47
|
+
'shape',
|
|
48
|
+
'textbox',
|
|
49
|
+
'connector',
|
|
50
|
+
'group',
|
|
51
|
+
'picture',
|
|
52
|
+
'video',
|
|
53
|
+
'audio',
|
|
54
|
+
'table',
|
|
55
|
+
'chart',
|
|
56
|
+
],
|
|
57
|
+
pictureInput: ['base64', 'path'],
|
|
58
|
+
picture: { replacePicture: true, cleanupUnreferencedMedia: true },
|
|
59
|
+
media: { video: true, audio: true, autoPoster: true },
|
|
60
|
+
chart: {
|
|
61
|
+
create: true,
|
|
62
|
+
families: ['bar', 'column', 'line', 'pie', 'combo'],
|
|
63
|
+
basicOnly: editionCapabilities.chartBasicOnly,
|
|
64
|
+
title: true,
|
|
65
|
+
seriesCache: true,
|
|
66
|
+
seriesColor: true,
|
|
67
|
+
textColor: true,
|
|
68
|
+
gapWidth: true,
|
|
69
|
+
showMajorGridlines: true,
|
|
70
|
+
showDataLabels: true,
|
|
71
|
+
valueFormatCode: true,
|
|
72
|
+
comboDualAxis: true,
|
|
73
|
+
fill: true,
|
|
74
|
+
embeddedWorkbook: false,
|
|
75
|
+
},
|
|
76
|
+
table: {
|
|
77
|
+
insertRow: true,
|
|
78
|
+
deleteRow: true,
|
|
79
|
+
insertColumn: true,
|
|
80
|
+
deleteColumn: true,
|
|
81
|
+
cellFill: true,
|
|
82
|
+
heightAuto: true,
|
|
83
|
+
themes: ['minimal', 'zebra'],
|
|
84
|
+
alignColumns: true,
|
|
85
|
+
},
|
|
86
|
+
placeholder: { index: true, address: true, roleOnAdd: true },
|
|
87
|
+
hyperlink: { set: true, clear: true },
|
|
88
|
+
notes: { ensureOnWrite: true },
|
|
89
|
+
properties: {
|
|
90
|
+
text: true,
|
|
91
|
+
name: true,
|
|
92
|
+
srgbClr: true,
|
|
93
|
+
fill: true,
|
|
94
|
+
fillTransparency: true,
|
|
95
|
+
stroke: true,
|
|
96
|
+
textColor: true,
|
|
97
|
+
fontFamily: true,
|
|
98
|
+
fontSize: true,
|
|
99
|
+
bold: true,
|
|
100
|
+
italic: true,
|
|
101
|
+
underline: true,
|
|
102
|
+
hidden: true,
|
|
103
|
+
paragraphAlign: true,
|
|
104
|
+
paragraphLevel: true,
|
|
105
|
+
bullet: true,
|
|
106
|
+
hyperlink: true,
|
|
107
|
+
dotted: [
|
|
108
|
+
'font.family',
|
|
109
|
+
'font.size',
|
|
110
|
+
'font.weight',
|
|
111
|
+
'font.italic',
|
|
112
|
+
'font.underline',
|
|
113
|
+
'font.color',
|
|
114
|
+
'fill.color',
|
|
115
|
+
'fill.kind',
|
|
116
|
+
'fill.transparency',
|
|
117
|
+
'line.color',
|
|
118
|
+
'line.kind',
|
|
119
|
+
'line.width',
|
|
120
|
+
'text.value',
|
|
121
|
+
'visible',
|
|
122
|
+
'paragraph.align',
|
|
123
|
+
'paragraph.level',
|
|
124
|
+
'bullet',
|
|
125
|
+
'hyperlink',
|
|
126
|
+
],
|
|
127
|
+
aliases: {
|
|
128
|
+
stroke: ['border', 'outline', 'line'],
|
|
129
|
+
fontFamily: ['font', 'typeface'],
|
|
130
|
+
fontSize: ['size'],
|
|
131
|
+
textColor: ['fontColor'],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
query: { matchAll: ['*', 'all'], textRegex: true, hasText: true },
|
|
135
|
+
text: {
|
|
136
|
+
setText: true,
|
|
137
|
+
replaceText: true,
|
|
138
|
+
multiParagraph: true,
|
|
139
|
+
richRuns: true,
|
|
140
|
+
paragraphBlocks: true,
|
|
141
|
+
},
|
|
142
|
+
geometry: {
|
|
143
|
+
units: ['emu', 'px', 'pt', 'cm', 'mm', 'in', '%'],
|
|
144
|
+
alignElements: true,
|
|
145
|
+
cornerRadius: true,
|
|
146
|
+
},
|
|
147
|
+
textBox: { wrap: true, anchor: true },
|
|
148
|
+
measure: { heuristic: true },
|
|
149
|
+
shapes: {
|
|
150
|
+
lineIsStraightConnector: true,
|
|
151
|
+
elbowConnector: true,
|
|
152
|
+
curvedConnector: true,
|
|
153
|
+
arrows: ['rightArrow', 'leftArrow', 'upArrow', 'downArrow'],
|
|
154
|
+
flow: [
|
|
155
|
+
'chevron',
|
|
156
|
+
'homePlate',
|
|
157
|
+
'trapezoid',
|
|
158
|
+
'triangle',
|
|
159
|
+
'rtTriangle',
|
|
160
|
+
'circularArrow',
|
|
161
|
+
'curvedRightArrow',
|
|
162
|
+
'curvedLeftArrow',
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
history: { undo: true },
|
|
166
|
+
addressing: { targetPath: true, uid: true, placeholder: true, notes: true, runFocus: true },
|
|
167
|
+
resolve: { effective: true, direct: true, both: true, provenance: true },
|
|
168
|
+
preservation: 'unknown parts and untouched XML are preserved; ZIP entries are recompressed',
|
|
169
|
+
propertyVocabulary: {
|
|
170
|
+
note: 'Prefer deckuse schema --json for full command schemas. Capabilities flags are coarse.',
|
|
171
|
+
paragraphAlign: {
|
|
172
|
+
key: 'paragraph.align',
|
|
173
|
+
values: ['l', 'ctr', 'r', 'just'],
|
|
174
|
+
aliases: { left: 'l', center: 'ctr', right: 'r', justify: 'just' },
|
|
175
|
+
},
|
|
176
|
+
richText: {
|
|
177
|
+
blocks: 'one paragraph per block; optional runs[] for intra-paragraph styling',
|
|
178
|
+
runTarget: 'slide:N/shape:X/run:K for setProperties on a single run',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
const openWorkspaceArchive = async (workspace) => OpcArchive.openDirectory(sourceDir(workspace));
|
|
183
|
+
const validateArchive = (archive) => {
|
|
184
|
+
const diagnostics = [];
|
|
185
|
+
for (const [source, rels] of archive.relationships)
|
|
186
|
+
for (const rel of rels)
|
|
187
|
+
if (!rel.external && rel.resolvedTarget && !archive.getPart(rel.resolvedTarget))
|
|
188
|
+
diagnostics.push({
|
|
189
|
+
severity: 'error',
|
|
190
|
+
code: 'BROKEN_RELATIONSHIP',
|
|
191
|
+
message: `Missing target ${rel.resolvedTarget}`,
|
|
192
|
+
details: { source, relationshipId: rel.id },
|
|
193
|
+
});
|
|
194
|
+
// ZIP entries that differ only by case collide on macOS/Windows extract.
|
|
195
|
+
const seenNames = new Map();
|
|
196
|
+
for (const name of archive.parts.keys()) {
|
|
197
|
+
const key = name.toLowerCase();
|
|
198
|
+
const previous = seenNames.get(key);
|
|
199
|
+
if (previous) {
|
|
200
|
+
diagnostics.push({
|
|
201
|
+
severity: 'error',
|
|
202
|
+
code: 'CASE_COLLIDING_PARTS',
|
|
203
|
+
message: `Parts ${previous} and ${name} differ only by case (PowerPoint will prompt to repair on case-insensitive systems)`,
|
|
204
|
+
details: { parts: [previous, name] },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
seenNames.set(key, name);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// app.xml <Slides> must match p:sldIdLst only — not p14:sectionLst/p14:sldId.
|
|
212
|
+
const appPart = archive.getPart('/docProps/app.xml');
|
|
213
|
+
if (appPart && archive.getPart('/ppt/presentation.xml')) {
|
|
214
|
+
const presentation = archive.readXml('/ppt/presentation.xml');
|
|
215
|
+
const list = descendants(presentation, 'sldIdLst').find((el) => el.namespaceURI === NS.p);
|
|
216
|
+
const slideCount = list
|
|
217
|
+
? descendants(list, 'sldId').filter((el) => el.namespaceURI === NS.p).length
|
|
218
|
+
: 0;
|
|
219
|
+
const app = archive.readXml('/docProps/app.xml');
|
|
220
|
+
const slidesEl = descendants(app, 'Slides').find((node) => !node.namespaceURI ||
|
|
221
|
+
node.namespaceURI ===
|
|
222
|
+
'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties');
|
|
223
|
+
const declared = slidesEl?.textContent?.trim();
|
|
224
|
+
if (declared !== undefined && declared !== '' && Number(declared) !== slideCount) {
|
|
225
|
+
diagnostics.push({
|
|
226
|
+
severity: 'error',
|
|
227
|
+
code: 'SLIDE_COUNT_MISMATCH',
|
|
228
|
+
message: `docProps/app.xml <Slides> is ${declared} but presentation has ${String(slideCount)} p:sldId entries (PowerPoint will prompt to repair)`,
|
|
229
|
+
details: { declared: Number(declared), actual: slideCount },
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return diagnostics;
|
|
234
|
+
};
|
|
235
|
+
const slidesFromOutcome = (outcome) => outcome?.slides ?? [];
|
|
236
|
+
const assertExpectRevision = (command, current) => {
|
|
237
|
+
if (command.expectRevision !== undefined) {
|
|
238
|
+
const expected = String(command.expectRevision);
|
|
239
|
+
if (expected !== current && expected !== 'latest')
|
|
240
|
+
return err('TRANSACTION_CONFLICT', `Expected revision ${expected}, current ${current}`);
|
|
241
|
+
}
|
|
242
|
+
if (command.transactionId !== undefined &&
|
|
243
|
+
command.transactionId !== current &&
|
|
244
|
+
command.transactionId !== 'latest')
|
|
245
|
+
return err('TRANSACTION_CONFLICT', `Expected transactionId ${current}`);
|
|
246
|
+
return undefined;
|
|
247
|
+
};
|
|
248
|
+
const listResource = (archive, index, resource, slide) => {
|
|
249
|
+
if (resource === 'paragraphs' ||
|
|
250
|
+
resource === 'tables' ||
|
|
251
|
+
resource === 'sections' ||
|
|
252
|
+
resource === 'styles' ||
|
|
253
|
+
resource === 'bookmarks') {
|
|
254
|
+
return err('UNSUPPORTED_CAPABILITY', `list ${resource} is a Word resource and is not available for PPTX`, [], { hint: 'Use slides, shapes, layouts, masters, or theme.' });
|
|
255
|
+
}
|
|
256
|
+
if (resource === 'slides') {
|
|
257
|
+
const layouts = orderedLayouts(index);
|
|
258
|
+
const layoutIndexByPart = new Map(layouts.map((item, i) => [item.partUri, i + 1]));
|
|
259
|
+
return index.elements
|
|
260
|
+
.filter((item) => item.kind === 'slide')
|
|
261
|
+
.map((item, i) => {
|
|
262
|
+
const layoutPart = slideLayoutPart(archive, item.partUri);
|
|
263
|
+
const layout = layoutPart !== undefined
|
|
264
|
+
? {
|
|
265
|
+
target: `layout:${layoutPart
|
|
266
|
+
.split('/')
|
|
267
|
+
.pop()
|
|
268
|
+
?.replace(/\.xml$/i, '') ?? layoutPart}`,
|
|
269
|
+
displayName: layoutDisplayName(archive, layoutPart),
|
|
270
|
+
...(layoutIndexByPart.has(layoutPart)
|
|
271
|
+
? { index: layoutIndexByPart.get(layoutPart) }
|
|
272
|
+
: {}),
|
|
273
|
+
}
|
|
274
|
+
: undefined;
|
|
275
|
+
return {
|
|
276
|
+
target: `slide:${i + 1}`,
|
|
277
|
+
uid: uidForItem(item),
|
|
278
|
+
index: i + 1,
|
|
279
|
+
slideId: item.slideId,
|
|
280
|
+
name: item.name,
|
|
281
|
+
titlePreview: item.text?.slice(0, 80),
|
|
282
|
+
partUri: item.partUri,
|
|
283
|
+
...(layout !== undefined ? { layout } : {}),
|
|
284
|
+
};
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
if (resource === 'shapes') {
|
|
288
|
+
if (slide === undefined)
|
|
289
|
+
return err('INVALID_COMMAND', 'list shapes requires --slide', [], {
|
|
290
|
+
hint: 'deckuse list shapes --slide <n> --json',
|
|
291
|
+
});
|
|
292
|
+
const slides = index.elements.filter((item) => item.kind === 'slide');
|
|
293
|
+
const slideItem = slides[slide - 1];
|
|
294
|
+
if (!slideItem)
|
|
295
|
+
return err('TARGET_NOT_FOUND', `slide:${slide} does not exist`, [], {
|
|
296
|
+
target: `slide:${slide}`,
|
|
297
|
+
});
|
|
298
|
+
return index.elements
|
|
299
|
+
.filter((item) => item.partUri === slideItem.partUri &&
|
|
300
|
+
!['slide', 'notes', 'master', 'layout', 'theme', 'tableCell'].includes(item.kind))
|
|
301
|
+
.map((item, z) => ({
|
|
302
|
+
target: targetPathForItem(index, item),
|
|
303
|
+
uid: uidForItem(item),
|
|
304
|
+
id: cNvPrIdOf(item),
|
|
305
|
+
name: item.name,
|
|
306
|
+
kind: item.kind,
|
|
307
|
+
role: item.payload?.['placeholder'] ?? item.payload?.['role'],
|
|
308
|
+
bbox: item.transform,
|
|
309
|
+
zOrder: z,
|
|
310
|
+
textPreview: item.text?.slice(0, 80),
|
|
311
|
+
parentId: item.parentId,
|
|
312
|
+
...(item.kind === 'chart'
|
|
313
|
+
? {
|
|
314
|
+
chartVariant: item.payload?.['chartVariant'] === 'basic' ||
|
|
315
|
+
item.payload?.['chartVariant'] === 'advanced'
|
|
316
|
+
? item.payload['chartVariant']
|
|
317
|
+
: 'advanced',
|
|
318
|
+
}
|
|
319
|
+
: {}),
|
|
320
|
+
}));
|
|
321
|
+
}
|
|
322
|
+
if (resource === 'layouts' || resource === 'masters') {
|
|
323
|
+
if (resource === 'layouts') {
|
|
324
|
+
return orderedLayouts(index).map((item, i) => ({
|
|
325
|
+
...layoutListMeta(archive, item, i + 1),
|
|
326
|
+
uid: uidForItem(item),
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
const kind = 'master';
|
|
330
|
+
return index.elements
|
|
331
|
+
.filter((item) => item.kind === kind)
|
|
332
|
+
.map((item) => ({
|
|
333
|
+
target: targetPathForItem(index, item),
|
|
334
|
+
uid: uidForItem(item),
|
|
335
|
+
name: item.partUri
|
|
336
|
+
.split('/')
|
|
337
|
+
.pop()
|
|
338
|
+
?.replace(/\.xml$/, ''),
|
|
339
|
+
partUri: item.partUri,
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
return index.elements
|
|
343
|
+
.filter((item) => item.kind === 'theme')
|
|
344
|
+
.map((item) => ({
|
|
345
|
+
target: 'theme',
|
|
346
|
+
uid: uidForItem(item),
|
|
347
|
+
partUri: item.partUri,
|
|
348
|
+
colors: item.payload?.['colors'],
|
|
349
|
+
}));
|
|
350
|
+
};
|
|
351
|
+
const transactionOpsToAtomic = (ops, workspaceId, transactionId) => {
|
|
352
|
+
const commands = [];
|
|
353
|
+
for (const op of ops) {
|
|
354
|
+
const kind = String(op['op'] ?? op['type'] ?? '');
|
|
355
|
+
const base = {
|
|
356
|
+
version: '2.0',
|
|
357
|
+
workspaceId,
|
|
358
|
+
transactionId,
|
|
359
|
+
};
|
|
360
|
+
if (kind === 'add-shape' || kind === 'addShape') {
|
|
361
|
+
const shapeType = String(op['shapeType'] ?? op['type'] ?? 'text');
|
|
362
|
+
const allowed = new Set([
|
|
363
|
+
'text',
|
|
364
|
+
'rect',
|
|
365
|
+
'rounded-rect',
|
|
366
|
+
'ellipse',
|
|
367
|
+
'line',
|
|
368
|
+
'connector',
|
|
369
|
+
'elbow',
|
|
370
|
+
'elbow-connector',
|
|
371
|
+
'curved-connector',
|
|
372
|
+
'arrow',
|
|
373
|
+
'right-arrow',
|
|
374
|
+
'left-arrow',
|
|
375
|
+
'up-arrow',
|
|
376
|
+
'down-arrow',
|
|
377
|
+
'chevron',
|
|
378
|
+
'pentagon',
|
|
379
|
+
'trapezoid',
|
|
380
|
+
'triangle',
|
|
381
|
+
'rt-triangle',
|
|
382
|
+
'circular-arrow',
|
|
383
|
+
'curved-right-arrow',
|
|
384
|
+
'curved-left-arrow',
|
|
385
|
+
'image',
|
|
386
|
+
'group',
|
|
387
|
+
'table',
|
|
388
|
+
'chart',
|
|
389
|
+
'video',
|
|
390
|
+
'audio',
|
|
391
|
+
]);
|
|
392
|
+
if (!allowed.has(shapeType))
|
|
393
|
+
return err('UNSUPPORTED_CAPABILITY', `Unsupported shape type: ${shapeType}`);
|
|
394
|
+
commands.push({
|
|
395
|
+
...base,
|
|
396
|
+
type: 'addShape',
|
|
397
|
+
slide: Number(op['slide']),
|
|
398
|
+
shapeType: shapeType,
|
|
399
|
+
...(typeof op['name'] === 'string' ? { name: op['name'] } : {}),
|
|
400
|
+
...(typeof op['role'] === 'string' ? { role: op['role'] } : {}),
|
|
401
|
+
...(typeof op['x'] === 'number' ? { x: op['x'] } : {}),
|
|
402
|
+
...(typeof op['y'] === 'number' ? { y: op['y'] } : {}),
|
|
403
|
+
...(typeof op['width'] === 'number' ? { width: op['width'] } : {}),
|
|
404
|
+
...(typeof op['height'] === 'number' ? { height: op['height'] } : {}),
|
|
405
|
+
...(typeof op['file'] === 'string' ? { file: op['file'] } : {}),
|
|
406
|
+
...(typeof op['text'] === 'string' ? { text: op['text'] } : {}),
|
|
407
|
+
...(Array.isArray(op['rows']) ? { rows: op['rows'] } : {}),
|
|
408
|
+
...(typeof op['chartType'] === 'string'
|
|
409
|
+
? { chartType: op['chartType'] }
|
|
410
|
+
: {}),
|
|
411
|
+
...(op['data'] !== undefined && typeof op['data'] === 'object' && op['data'] !== null
|
|
412
|
+
? {
|
|
413
|
+
data: op['data'],
|
|
414
|
+
}
|
|
415
|
+
: {}),
|
|
416
|
+
});
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (kind === 'set-text' || kind === 'setText') {
|
|
420
|
+
commands.push({
|
|
421
|
+
...base,
|
|
422
|
+
type: 'setText',
|
|
423
|
+
target: String(op['target']),
|
|
424
|
+
value: String(op['value'] ?? op['text'] ?? ''),
|
|
425
|
+
});
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (kind === 'set') {
|
|
429
|
+
const { op: _op, type: _type, target, ...rest } = op;
|
|
430
|
+
const properties = op['properties'] ?? rest;
|
|
431
|
+
const cleaned = { ...properties };
|
|
432
|
+
delete cleaned['target'];
|
|
433
|
+
delete cleaned['op'];
|
|
434
|
+
delete cleaned['type'];
|
|
435
|
+
commands.push({
|
|
436
|
+
...base,
|
|
437
|
+
type: 'set',
|
|
438
|
+
target: String(target),
|
|
439
|
+
properties: cleaned,
|
|
440
|
+
scope: 'local',
|
|
441
|
+
});
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (kind === 'add-slide' || kind === 'addSlide') {
|
|
445
|
+
commands.push({
|
|
446
|
+
...base,
|
|
447
|
+
type: 'addSlide',
|
|
448
|
+
...(typeof op['after'] === 'number' ? { after: op['after'] } : {}),
|
|
449
|
+
...(typeof op['layout'] === 'string' ? { layout: op['layout'] } : {}),
|
|
450
|
+
...(typeof op['name'] === 'string' ? { name: op['name'] } : {}),
|
|
451
|
+
});
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
if (kind === 'remove') {
|
|
455
|
+
commands.push({ ...base, type: 'remove', target: String(op['target']) });
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
return err('UNSUPPORTED_CAPABILITY', `Unsupported transaction op: ${kind || '(missing)'}`);
|
|
459
|
+
}
|
|
460
|
+
return ok(commands);
|
|
461
|
+
};
|
|
462
|
+
export const pptxAdapter = {
|
|
463
|
+
format: 'pptx',
|
|
464
|
+
version: VERSION,
|
|
465
|
+
async init(command) {
|
|
466
|
+
try {
|
|
467
|
+
const workspace = resolve(command.workspaceId);
|
|
468
|
+
const archive = await OpcArchive.openFile(resolve(command.source));
|
|
469
|
+
if (!archive.getPart('/ppt/presentation.xml'))
|
|
470
|
+
return err('VALIDATION_FAILED', 'Not a PPTX presentation');
|
|
471
|
+
// Real-world decks (templates, iSlide, etc.) often ship stale app.xml <Slides>.
|
|
472
|
+
// Normalize on import so validate / first writes are not blocked by pre-existing drift.
|
|
473
|
+
syncAppSlideCounts(archive);
|
|
474
|
+
const created = new Date().toISOString(), rev = revision();
|
|
475
|
+
const manifest = {
|
|
476
|
+
schemaVersion: '2.0',
|
|
477
|
+
workspaceId: workspace,
|
|
478
|
+
format: 'pptx',
|
|
479
|
+
source: resolve(command.source),
|
|
480
|
+
revision: rev,
|
|
481
|
+
createdAt: created,
|
|
482
|
+
updatedAt: created,
|
|
483
|
+
adapterVersion: VERSION,
|
|
484
|
+
files: [],
|
|
485
|
+
metadata: { capabilities: pptxCapabilities },
|
|
486
|
+
};
|
|
487
|
+
const index = buildIndex(archive, workspace, rev);
|
|
488
|
+
const saved = await initializeWorkspace(workspace, archive, manifest, index);
|
|
489
|
+
return ok({
|
|
490
|
+
workspaceId: saved.workspaceId,
|
|
491
|
+
format: saved.format,
|
|
492
|
+
source: saved.source,
|
|
493
|
+
revision: saved.revision,
|
|
494
|
+
elementCount: index.elements.length,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
catch (cause) {
|
|
498
|
+
return err('IO_ERROR', cause instanceof Error ? cause.message : 'PPTX init failed');
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
async execute(command) {
|
|
502
|
+
const workspace = resolve(command.workspaceId);
|
|
503
|
+
try {
|
|
504
|
+
if (command.type === 'undo') {
|
|
505
|
+
return await withWriteLock(workspace, async () => {
|
|
506
|
+
try {
|
|
507
|
+
const result = await undoWrites(workspace, command.steps);
|
|
508
|
+
return ok(result);
|
|
509
|
+
}
|
|
510
|
+
catch (cause) {
|
|
511
|
+
return err('VALIDATION_FAILED', cause instanceof Error ? cause.message : 'Undo failed');
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
if (command.type === 'history') {
|
|
516
|
+
const { records, total } = await readHistory(workspace, command.limit, command.offset);
|
|
517
|
+
const filtered = command.slide !== undefined
|
|
518
|
+
? records.filter((record) => record.slides.includes(command.slide))
|
|
519
|
+
: records;
|
|
520
|
+
return ok({
|
|
521
|
+
records: filtered,
|
|
522
|
+
total: command.slide !== undefined ? filtered.length : total,
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
const manifest = await readManifest(workspace);
|
|
526
|
+
if (manifest.schemaVersion !== '2.0' || !isIntegerRevision(manifest.revision)) {
|
|
527
|
+
if (command.type === 'status') {
|
|
528
|
+
return ok({
|
|
529
|
+
workspaceId: workspace,
|
|
530
|
+
format: manifest.format,
|
|
531
|
+
revision: manifest.revision,
|
|
532
|
+
schemaVersion: manifest.schemaVersion,
|
|
533
|
+
compatible: false,
|
|
534
|
+
hint: 'Re-run deckuse init to upgrade this workspace to protocol 2.0.',
|
|
535
|
+
capabilities: manifest.metadata?.['capabilities'],
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const archive = await openWorkspaceArchive(workspace);
|
|
540
|
+
const index = await loadIndex(workspace, archive, manifest, { persist: true });
|
|
541
|
+
if (command.type === 'status') {
|
|
542
|
+
return ok({
|
|
543
|
+
workspaceId: workspace,
|
|
544
|
+
format: manifest.format,
|
|
545
|
+
revision: manifest.revision,
|
|
546
|
+
schemaVersion: manifest.schemaVersion,
|
|
547
|
+
compatible: true,
|
|
548
|
+
adapterVersion: manifest.adapterVersion,
|
|
549
|
+
source: manifest.source,
|
|
550
|
+
package: packagePath(workspace),
|
|
551
|
+
packageStale: await isPackageStale(workspace, manifest),
|
|
552
|
+
elementCount: index.elements.length,
|
|
553
|
+
capabilities: pptxCapabilities,
|
|
554
|
+
...editionMetadata,
|
|
555
|
+
branch: 'main',
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
if (command.type === 'list') {
|
|
559
|
+
const listed = listResource(archive, index, command.resource, command.slide);
|
|
560
|
+
if (listed && typeof listed === 'object' && 'ok' in listed && listed.ok === false)
|
|
561
|
+
return listed;
|
|
562
|
+
return ok({ resource: command.resource, items: listed });
|
|
563
|
+
}
|
|
564
|
+
if (command.type === 'get') {
|
|
565
|
+
const resolved = resolveTarget(index, command.target);
|
|
566
|
+
if (!resolved.ok)
|
|
567
|
+
return resolved;
|
|
568
|
+
const details = resolveProperties(archive, resolved.value, {
|
|
569
|
+
resolve: command.resolve,
|
|
570
|
+
...(command.props ? { props: command.props } : {}),
|
|
571
|
+
provenance: command.provenance ?? true,
|
|
572
|
+
});
|
|
573
|
+
return ok(details);
|
|
574
|
+
}
|
|
575
|
+
if (command.type === 'search') {
|
|
576
|
+
const items = index.elements.filter((item) => {
|
|
577
|
+
if (command.kind === 'text') {
|
|
578
|
+
if (!item.text)
|
|
579
|
+
return false;
|
|
580
|
+
if (command.query && !item.text.toLowerCase().includes(command.query.toLowerCase()))
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
if (command.name && item.name !== command.name)
|
|
585
|
+
return false;
|
|
586
|
+
if (command.query &&
|
|
587
|
+
!(item.name ?? '').toLowerCase().includes(command.query.toLowerCase()))
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
return true;
|
|
591
|
+
});
|
|
592
|
+
if (command.kind === 'shape' && command.name) {
|
|
593
|
+
const named = items.filter((item) => item.name === command.name);
|
|
594
|
+
if (named.length > 1)
|
|
595
|
+
return err('AMBIGUOUS_NAME', `Shape name is ambiguous: ${command.name}`);
|
|
596
|
+
}
|
|
597
|
+
return ok({
|
|
598
|
+
matches: items.slice(0, command.limit).map((item) => ({
|
|
599
|
+
target: targetPathForItem(index, item),
|
|
600
|
+
uid: uidForItem(item),
|
|
601
|
+
name: item.name,
|
|
602
|
+
kind: item.kind,
|
|
603
|
+
text: item.text?.slice(0, 200),
|
|
604
|
+
context: item.partUri,
|
|
605
|
+
})),
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (command.type === 'inspect') {
|
|
609
|
+
if (command.target) {
|
|
610
|
+
const resolved = resolveTarget(index, command.target);
|
|
611
|
+
if (!resolved.ok)
|
|
612
|
+
return resolved;
|
|
613
|
+
const details = resolveProperties(archive, resolved.value, {
|
|
614
|
+
resolve: 'both',
|
|
615
|
+
provenance: true,
|
|
616
|
+
});
|
|
617
|
+
return ok({
|
|
618
|
+
target: resolved.value.target,
|
|
619
|
+
uid: resolved.value.uid,
|
|
620
|
+
kind: resolved.value.item.kind,
|
|
621
|
+
name: resolved.value.item.name,
|
|
622
|
+
partUri: resolved.value.item.partUri,
|
|
623
|
+
transform: resolved.value.item.transform,
|
|
624
|
+
visualTree: command.visualTree
|
|
625
|
+
? index.elements
|
|
626
|
+
.filter((item) => item.partUri === resolved.value.item.partUri)
|
|
627
|
+
.map((item) => ({
|
|
628
|
+
target: targetPathForItem(index, item),
|
|
629
|
+
kind: item.kind,
|
|
630
|
+
name: item.name,
|
|
631
|
+
}))
|
|
632
|
+
: undefined,
|
|
633
|
+
properties: details.properties,
|
|
634
|
+
warnings: details.warnings,
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (command.ref) {
|
|
638
|
+
const item = findIndexed(index, command.ref);
|
|
639
|
+
return item ? ok(item) : err('ELEMENT_NOT_FOUND', 'Element reference was not found');
|
|
640
|
+
}
|
|
641
|
+
return ok({
|
|
642
|
+
document: { format: 'pptx', revision: index.revision, capabilities: pptxCapabilities },
|
|
643
|
+
elements: index.elements,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
if (command.type === 'query')
|
|
647
|
+
return ok(index.elements
|
|
648
|
+
.filter((item) => matchesSelector(item, command.selector))
|
|
649
|
+
.slice(0, command.limit));
|
|
650
|
+
if (command.type === 'getText') {
|
|
651
|
+
const item = findIndexed(index, command.ref);
|
|
652
|
+
return item
|
|
653
|
+
? ok({
|
|
654
|
+
ref: item.ref,
|
|
655
|
+
target: targetPathForItem(index, item),
|
|
656
|
+
uid: uidForItem(item),
|
|
657
|
+
slide: item.slideId,
|
|
658
|
+
text: item.text ?? '',
|
|
659
|
+
kind: item.kind,
|
|
660
|
+
geometry: item.transform,
|
|
661
|
+
location: item.location,
|
|
662
|
+
payload: item.kind === 'chart' ||
|
|
663
|
+
item.kind === 'picture' ||
|
|
664
|
+
item.kind === 'video' ||
|
|
665
|
+
item.kind === 'audio'
|
|
666
|
+
? item.payload
|
|
667
|
+
: undefined,
|
|
668
|
+
})
|
|
669
|
+
: err('ELEMENT_NOT_FOUND', 'Element reference was not found');
|
|
670
|
+
}
|
|
671
|
+
if (command.type === 'validate') {
|
|
672
|
+
const diagnostics = validateArchive(archive);
|
|
673
|
+
return diagnostics.length
|
|
674
|
+
? err('VALIDATION_FAILED', 'PPTX validation failed', diagnostics)
|
|
675
|
+
: ok({
|
|
676
|
+
valid: true,
|
|
677
|
+
revision: index.revision,
|
|
678
|
+
capabilities: pptxCapabilities,
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
if (command.type === 'export') {
|
|
682
|
+
if (command.revision !== undefined && String(command.revision) !== manifest.revision)
|
|
683
|
+
return err('UNSUPPORTED_CAPABILITY', 'Export of historical revisions is not available in Phase 1a', [], { hint: 'Omit --revision to export the current workspace package.' });
|
|
684
|
+
const output = resolve(command.output);
|
|
685
|
+
const fromPackage = command.fromPackage === true;
|
|
686
|
+
let repacked = false;
|
|
687
|
+
let exportRevision = manifest.revision;
|
|
688
|
+
if (!fromPackage) {
|
|
689
|
+
const packed = await repackWorkspace(workspace);
|
|
690
|
+
exportRevision = packed.manifest.revision;
|
|
691
|
+
repacked = true;
|
|
692
|
+
}
|
|
693
|
+
await copyFile(packagePath(workspace), output);
|
|
694
|
+
return ok({
|
|
695
|
+
output,
|
|
696
|
+
revision: exportRevision,
|
|
697
|
+
repacked,
|
|
698
|
+
fromPackage,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
if (!WRITE_TYPES.has(command.type))
|
|
702
|
+
return err('INVALID_COMMAND', `Unsupported command type: ${command.type}`);
|
|
703
|
+
const conflict = assertExpectRevision(command, manifest.revision);
|
|
704
|
+
if (conflict)
|
|
705
|
+
return conflict;
|
|
706
|
+
return await withWriteLock(workspace, async () => {
|
|
707
|
+
const currentManifest = await readManifest(workspace);
|
|
708
|
+
const locked = assertExpectRevision(command, currentManifest.revision);
|
|
709
|
+
if (locked)
|
|
710
|
+
return locked;
|
|
711
|
+
const working = await openWorkspaceArchive(workspace);
|
|
712
|
+
let currentIndex = await loadIndex(workspace, working, currentManifest);
|
|
713
|
+
const STRUCTURAL_TYPES = new Set([
|
|
714
|
+
'addShape',
|
|
715
|
+
'addSlide',
|
|
716
|
+
'setSlideLayout',
|
|
717
|
+
'remove',
|
|
718
|
+
'duplicate',
|
|
719
|
+
'add',
|
|
720
|
+
'replacePicture',
|
|
721
|
+
]);
|
|
722
|
+
const runBatch = async (nestedCommands, dryRun, operation) => {
|
|
723
|
+
const results = [];
|
|
724
|
+
const diagnostics = [];
|
|
725
|
+
const slidePages = [];
|
|
726
|
+
const changedTargets = [];
|
|
727
|
+
const changedParts = [];
|
|
728
|
+
for (const nested of nestedCommands) {
|
|
729
|
+
const result = await mutate(nested, working, currentIndex);
|
|
730
|
+
diagnostics.push(...result.diagnostics);
|
|
731
|
+
if (!result.ok)
|
|
732
|
+
return result;
|
|
733
|
+
results.push(result.value);
|
|
734
|
+
slidePages.push(...slidesFromOutcome(result.value));
|
|
735
|
+
if (result.value.changedTargets)
|
|
736
|
+
changedTargets.push(...result.value.changedTargets);
|
|
737
|
+
if (result.value.changedParts)
|
|
738
|
+
changedParts.push(...result.value.changedParts);
|
|
739
|
+
if (STRUCTURAL_TYPES.has(nested.type)) {
|
|
740
|
+
currentIndex = buildIndex(working, currentManifest.workspaceId, currentManifest.revision);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
// Heal pre-existing app.xml drift (and Notes) before the integrity gate.
|
|
744
|
+
syncAppSlideCounts(working);
|
|
745
|
+
const validation = validateArchive(working);
|
|
746
|
+
if (validation.length)
|
|
747
|
+
return err('VALIDATION_FAILED', 'PPTX validation failed', validation);
|
|
748
|
+
if (dryRun)
|
|
749
|
+
return ok({
|
|
750
|
+
results,
|
|
751
|
+
revision: currentManifest.revision,
|
|
752
|
+
dryRun: true,
|
|
753
|
+
changedTargets: [...new Set(changedTargets)],
|
|
754
|
+
changedParts: [...new Set(changedParts)],
|
|
755
|
+
affectedSlides: mergeSlides(slidePages),
|
|
756
|
+
}, diagnostics);
|
|
757
|
+
const rev = nextRevision(currentManifest.revision);
|
|
758
|
+
const nextIndex = buildIndex(working, currentManifest.workspaceId, rev);
|
|
759
|
+
const saved = await persistWrite(workspace, working, currentManifest, nextIndex, operation, mergeSlides(slidePages));
|
|
760
|
+
return ok({
|
|
761
|
+
results,
|
|
762
|
+
revision: saved.revision,
|
|
763
|
+
changedTargets: [...new Set(changedTargets)],
|
|
764
|
+
changedParts: [...new Set(changedParts)],
|
|
765
|
+
affectedSlides: mergeSlides(slidePages),
|
|
766
|
+
}, diagnostics);
|
|
767
|
+
};
|
|
768
|
+
if (command.type === 'applyTransaction') {
|
|
769
|
+
const mapped = transactionOpsToAtomic(command.operations, command.workspaceId, command.transactionId);
|
|
770
|
+
if (!mapped.ok)
|
|
771
|
+
return mapped;
|
|
772
|
+
return runBatch(mapped.value, command.dryRun, command);
|
|
773
|
+
}
|
|
774
|
+
if (command.type === 'batch') {
|
|
775
|
+
return runBatch(command.commands, command.dryRun, command);
|
|
776
|
+
}
|
|
777
|
+
const result = await mutate(command, working, currentIndex);
|
|
778
|
+
if (!result.ok)
|
|
779
|
+
return result;
|
|
780
|
+
// Heal pre-existing app.xml drift (and Notes) before the integrity gate.
|
|
781
|
+
syncAppSlideCounts(working);
|
|
782
|
+
const validation = validateArchive(working);
|
|
783
|
+
if (validation.length)
|
|
784
|
+
return err('VALIDATION_FAILED', 'PPTX validation failed', validation);
|
|
785
|
+
if (command.dryRun)
|
|
786
|
+
return ok({
|
|
787
|
+
...result.value,
|
|
788
|
+
revision: currentManifest.revision,
|
|
789
|
+
dryRun: true,
|
|
790
|
+
affectedSlides: slidesFromOutcome(result.value),
|
|
791
|
+
}, result.diagnostics);
|
|
792
|
+
const rev = nextRevision(currentManifest.revision);
|
|
793
|
+
const nextIndex = buildIndex(working, currentManifest.workspaceId, rev);
|
|
794
|
+
const saved = await persistWrite(workspace, working, currentManifest, nextIndex, command, slidesFromOutcome(result.value));
|
|
795
|
+
return ok({
|
|
796
|
+
...result.value,
|
|
797
|
+
revision: saved.revision,
|
|
798
|
+
affectedSlides: slidesFromOutcome(result.value),
|
|
799
|
+
}, result.diagnostics);
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
catch (cause) {
|
|
803
|
+
return err('IO_ERROR', cause instanceof Error ? cause.message : 'PPTX operation failed');
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
};
|
|
807
|
+
//# sourceMappingURL=adapter.js.map
|