deckjsx 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.d.mts +42 -5
- package/dist/index.mjs +931 -25
- package/dist/jsx-Crlbye9V.mjs +290 -0
- package/dist/jsx-dev-runtime.d.mts +6 -2
- package/dist/jsx-dev-runtime.mjs +17 -2
- package/dist/{jsx-runtime-BWV9tOov.d.mts → jsx-runtime-DauuRkY2.d.mts} +277 -29
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/jsx-runtime.mjs +3 -3
- package/package.json +1 -1
- package/dist/jsx-lqMAdW2X.mjs +0 -175
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as isContentNode, c as toLegacyJsxNode, d as Slide, f as Text, i as isAuthorNode, l as Image, m as isAuthorTreeNode, n as createElement, o as isSlideNode, p as View, s as isLegacyAuthorNode, t as Fragment, u as Shape } from "./jsx-Crlbye9V.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname } from "node:path";
|
|
@@ -3863,24 +3863,15 @@ function compileGroupNode(node, parentFrame, idGenerator, placement, clipRect, c
|
|
|
3863
3863
|
}, childClipRect, context)
|
|
3864
3864
|
};
|
|
3865
3865
|
}
|
|
3866
|
-
function
|
|
3867
|
-
const { props } = node;
|
|
3868
|
-
const textLengthContext = getTextLengthContext(props, context);
|
|
3869
|
-
const resolved = frameFromProps(props, parentFrame, placement, textLengthContext);
|
|
3870
|
-
const strokes = resolveNodeStrokes(props, textLengthContext);
|
|
3871
|
-
const shadow = parseShadowShorthand(props.textShadow ?? props.boxShadow);
|
|
3866
|
+
function textStyleFromProps(props, textLengthContext) {
|
|
3872
3867
|
const list = resolveListStyle(props, textLengthContext);
|
|
3873
3868
|
const lineHeight = resolveLineHeight(props.lineHeight, textLengthContext);
|
|
3874
3869
|
const underlineStyle = resolveUnderlineStyle(props.textDecorationStyle);
|
|
3875
3870
|
const underlineColor = normalizeColor(props.textDecorationColor);
|
|
3876
3871
|
const textDirection = resolveTextDirection(props.writingMode);
|
|
3877
3872
|
const tabStops = resolveTabStops(props.tabStops, textLengthContext);
|
|
3878
|
-
const hyperlink = props.href ? {
|
|
3879
|
-
url: props.href,
|
|
3880
|
-
...props.tooltip ? { tooltip: props.tooltip } : {}
|
|
3881
|
-
} : void 0;
|
|
3882
3873
|
const fontSizePt = props.fontSize === void 0 ? void 0 : parsePointValue(props.fontSize, 0, textLengthContext);
|
|
3883
|
-
|
|
3874
|
+
return {
|
|
3884
3875
|
fontFamily: props.fontFamily,
|
|
3885
3876
|
fontSizePt,
|
|
3886
3877
|
fontWeight: props.fontWeight,
|
|
@@ -3908,6 +3899,48 @@ function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, co
|
|
|
3908
3899
|
...props.superscript ? { superscript: true } : {},
|
|
3909
3900
|
...props.subscript ? { subscript: true } : {}
|
|
3910
3901
|
};
|
|
3902
|
+
}
|
|
3903
|
+
function isEmptyRunStyle(style) {
|
|
3904
|
+
return Object.values(style).every((value) => value === void 0);
|
|
3905
|
+
}
|
|
3906
|
+
function flattenUnknownChildren(children) {
|
|
3907
|
+
return children.flatMap((child) => Array.isArray(child) ? flattenUnknownChildren(child) : [child]);
|
|
3908
|
+
}
|
|
3909
|
+
function extractRichTextRuns(children, textTransform, textLengthContext) {
|
|
3910
|
+
const runs = [];
|
|
3911
|
+
for (const child of flattenUnknownChildren(children)) {
|
|
3912
|
+
if (child === null || child === void 0 || child === false || child === true) continue;
|
|
3913
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
3914
|
+
runs.push({ text: extractText([child], textTransform) });
|
|
3915
|
+
continue;
|
|
3916
|
+
}
|
|
3917
|
+
if (typeof child === "object" && child !== null && "kind" in child) {
|
|
3918
|
+
const authorNode = child;
|
|
3919
|
+
if (authorNode.kind !== "text") throw new Error("Text nodes can only contain primitive text or inline text runs.");
|
|
3920
|
+
const props = normalizeTextProps(authorNode.props);
|
|
3921
|
+
const childLengthContext = getTextLengthContext(props, textLengthContext);
|
|
3922
|
+
const style = textStyleFromProps(props, childLengthContext);
|
|
3923
|
+
const text = extractRichTextRuns(authorNode.children, props.textTransform ?? textTransform, childLengthContext).map((run) => run.text).join("");
|
|
3924
|
+
runs.push({
|
|
3925
|
+
text,
|
|
3926
|
+
...!isEmptyRunStyle(style) ? { style } : {}
|
|
3927
|
+
});
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
return runs;
|
|
3931
|
+
}
|
|
3932
|
+
function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, context) {
|
|
3933
|
+
const { props } = node;
|
|
3934
|
+
const textLengthContext = getTextLengthContext(props, context);
|
|
3935
|
+
const resolved = frameFromProps(props, parentFrame, placement, textLengthContext);
|
|
3936
|
+
const strokes = resolveNodeStrokes(props, textLengthContext);
|
|
3937
|
+
const shadow = parseShadowShorthand(props.textShadow ?? props.boxShadow);
|
|
3938
|
+
const hyperlink = props.href ? {
|
|
3939
|
+
url: props.href,
|
|
3940
|
+
...props.tooltip ? { tooltip: props.tooltip } : {}
|
|
3941
|
+
} : void 0;
|
|
3942
|
+
const style = textStyleFromProps(props, textLengthContext);
|
|
3943
|
+
const runs = extractRichTextRuns(node.source.children, props.textTransform, textLengthContext);
|
|
3911
3944
|
const visibleFrame = intersectClipRect({
|
|
3912
3945
|
xEmu: resolved.xEmu,
|
|
3913
3946
|
yEmu: resolved.yEmu,
|
|
@@ -3930,7 +3963,10 @@ function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, co
|
|
|
3930
3963
|
...props.visibility !== void 0 ? { visibility: props.visibility } : {},
|
|
3931
3964
|
flipH: resolved.flipH,
|
|
3932
3965
|
flipV: resolved.flipV,
|
|
3933
|
-
content: {
|
|
3966
|
+
content: {
|
|
3967
|
+
text: runs.map((run) => run.text).join(""),
|
|
3968
|
+
...runs.length > 1 || runs.some((run) => run.style) ? { runs } : {}
|
|
3969
|
+
},
|
|
3934
3970
|
style,
|
|
3935
3971
|
fill: backgroundFill.fill,
|
|
3936
3972
|
...backgroundFill.backgroundLayers ? { backgroundLayers: backgroundFill.backgroundLayers } : {},
|
|
@@ -4102,13 +4138,775 @@ function renderPresentation(options, slides) {
|
|
|
4102
4138
|
version: "0.1",
|
|
4103
4139
|
meta: options.meta,
|
|
4104
4140
|
size: slideSize,
|
|
4105
|
-
slides: slides.map((factory, slideIndex) =>
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4141
|
+
slides: slides.map((factory, slideIndex) => {
|
|
4142
|
+
return compileSlide(toLegacyJsxNode(factory({ composition: {
|
|
4143
|
+
slideIndex,
|
|
4144
|
+
totalSlides: slides.length,
|
|
4145
|
+
deckSlideIndex: slideIndex,
|
|
4146
|
+
deckTotalSlides: slides.length
|
|
4147
|
+
} })), { slideIndex }, slideFrame, idGenerator, lengthContext);
|
|
4148
|
+
})
|
|
4149
|
+
};
|
|
4150
|
+
}
|
|
4151
|
+
//#endregion
|
|
4152
|
+
//#region src/diagnostics/format.ts
|
|
4153
|
+
function formatSpan(path) {
|
|
4154
|
+
return ` at ${path}`;
|
|
4155
|
+
}
|
|
4156
|
+
function formatDiagnostic(diagnostic) {
|
|
4157
|
+
const lines = [`${diagnostic.severity}[${diagnostic.code}]: ${diagnostic.title}`];
|
|
4158
|
+
if (diagnostic.message) lines.push(` ${diagnostic.message}`);
|
|
4159
|
+
for (const label of diagnostic.labels) {
|
|
4160
|
+
lines.push(formatSpan(label.path));
|
|
4161
|
+
lines.push(` = ${label.message}`);
|
|
4162
|
+
}
|
|
4163
|
+
for (const note of diagnostic.notes ?? []) lines.push(`note: ${note}`);
|
|
4164
|
+
for (const help of diagnostic.help ?? []) lines.push(`help: ${help}`);
|
|
4165
|
+
return lines.join("\n");
|
|
4166
|
+
}
|
|
4167
|
+
function formatDiagnostics(diagnostics) {
|
|
4168
|
+
return diagnostics.items.map((item) => formatDiagnostic(item)).join("\n\n");
|
|
4169
|
+
}
|
|
4170
|
+
//#endregion
|
|
4171
|
+
//#region src/diagnostics/errors.ts
|
|
4172
|
+
var DeckDiagnosticError = class extends Error {
|
|
4173
|
+
diagnostics;
|
|
4174
|
+
constructor(message, diagnostics) {
|
|
4175
|
+
super(message);
|
|
4176
|
+
this.name = "DeckDiagnosticError";
|
|
4177
|
+
this.diagnostics = diagnostics;
|
|
4178
|
+
}
|
|
4179
|
+
};
|
|
4180
|
+
var SemanticGraphDiagnosticError = class extends DeckDiagnosticError {
|
|
4181
|
+
constructor(diagnostics) {
|
|
4182
|
+
super(formatDiagnostics(diagnostics), diagnostics);
|
|
4183
|
+
this.name = "SemanticGraphDiagnosticError";
|
|
4184
|
+
}
|
|
4185
|
+
};
|
|
4186
|
+
var CompositionDiagnosticError = class extends DeckDiagnosticError {
|
|
4187
|
+
constructor(diagnostics) {
|
|
4188
|
+
super(formatDiagnostics(diagnostics), diagnostics);
|
|
4189
|
+
this.name = "CompositionDiagnosticError";
|
|
4190
|
+
}
|
|
4191
|
+
};
|
|
4192
|
+
//#endregion
|
|
4193
|
+
//#region src/diagnostics/index.ts
|
|
4194
|
+
function createDiagnostics(items = []) {
|
|
4195
|
+
return {
|
|
4196
|
+
items,
|
|
4197
|
+
hasErrors: items.some((item) => item.severity === "error"),
|
|
4198
|
+
hasWarnings: items.some((item) => item.severity === "warning")
|
|
4199
|
+
};
|
|
4200
|
+
}
|
|
4201
|
+
function diagnostic(input) {
|
|
4202
|
+
return input;
|
|
4203
|
+
}
|
|
4204
|
+
//#endregion
|
|
4205
|
+
//#region src/composition/types.ts
|
|
4206
|
+
const COMPOSITION_SOURCE = Symbol("deckjsx.compositionSource");
|
|
4207
|
+
function sourceIdentity(value) {
|
|
4208
|
+
return value;
|
|
4209
|
+
}
|
|
4210
|
+
//#endregion
|
|
4211
|
+
//#region src/composition/resolve.ts
|
|
4212
|
+
const MAX_COMPOSITION_DEPTH = 64;
|
|
4213
|
+
const ROOT_SOURCE = { kind: "root" };
|
|
4214
|
+
function addDiagnostic$1(context, item) {
|
|
4215
|
+
context.diagnostics.push(item);
|
|
4216
|
+
}
|
|
4217
|
+
function compositionDiagnostic(input) {
|
|
4218
|
+
return diagnostic({
|
|
4219
|
+
severity: "error",
|
|
4220
|
+
code: input.code,
|
|
4221
|
+
title: input.title,
|
|
4222
|
+
message: input.message,
|
|
4223
|
+
labels: [{
|
|
4224
|
+
path: input.path,
|
|
4225
|
+
message: input.message
|
|
4226
|
+
}],
|
|
4227
|
+
...input.help ? { help: input.help } : {}
|
|
4228
|
+
});
|
|
4229
|
+
}
|
|
4230
|
+
function sourcePathFor(parentPath, sourceKey) {
|
|
4231
|
+
return parentPath === "root" ? sourceKey : `${parentPath}/${sourceKey}`;
|
|
4232
|
+
}
|
|
4233
|
+
function sourceOriginFor(parent, sourceKey) {
|
|
4234
|
+
return {
|
|
4235
|
+
kind: "mounted",
|
|
4236
|
+
sourceKey,
|
|
4237
|
+
sourceIdentity: sourceIdentity(`${parent.kind === "root" ? "" : `${parent.sourceIdentity}/`}${sourceKey}`)
|
|
4238
|
+
};
|
|
4239
|
+
}
|
|
4240
|
+
function sourceMaterialFor(source) {
|
|
4241
|
+
return source.kind === "root" ? ["source", "root"] : ["source", source.sourceIdentity];
|
|
4242
|
+
}
|
|
4243
|
+
function validateSourceKey(sourceKey) {
|
|
4244
|
+
if (sourceKey.trim().length === 0) return "Source Key must not be empty.";
|
|
4245
|
+
if (sourceKey === "." || sourceKey === "..") return "Source Key must not be dot or dot-dot.";
|
|
4246
|
+
if (sourceKey.includes("/")) return "Source Key must not contain /.";
|
|
4247
|
+
}
|
|
4248
|
+
function describeInvalidRoot(value) {
|
|
4249
|
+
if (isLegacyAuthorNode(value)) return "Slide factory returned a legacy author node.";
|
|
4250
|
+
if (isAuthorTreeNode(value)) return "Slide factory returned an author tree node that is not a <Slide /> root.";
|
|
4251
|
+
if (value === null) return "Slide factory returned null.";
|
|
4252
|
+
return `Slide factory returned ${typeof value}.`;
|
|
4253
|
+
}
|
|
4254
|
+
function isSlideRoot(value) {
|
|
4255
|
+
return value.kind === "element" && value.source.kind === "component" && value.source.component === "Slide";
|
|
4256
|
+
}
|
|
4257
|
+
function isPromiseLike(value) {
|
|
4258
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
4259
|
+
}
|
|
4260
|
+
function mapSlotOrigins(value, origin, targets, seen) {
|
|
4261
|
+
if (isAuthorTreeNode(value)) {
|
|
4262
|
+
targets.set(value, origin);
|
|
4263
|
+
return;
|
|
4264
|
+
}
|
|
4265
|
+
if (!Array.isArray(value)) return;
|
|
4266
|
+
if (seen.has(value)) return;
|
|
4267
|
+
seen.add(value);
|
|
4268
|
+
value.forEach((item) => mapSlotOrigins(item, origin, targets, seen));
|
|
4269
|
+
}
|
|
4270
|
+
function collectSourceSlots(context, parent) {
|
|
4271
|
+
const origins = /* @__PURE__ */ new WeakMap();
|
|
4272
|
+
if (!context.present || typeof context.value !== "object" || context.value === null) return origins;
|
|
4273
|
+
Object.entries(context.value).forEach(([field, value]) => {
|
|
4274
|
+
mapSlotOrigins(value, {
|
|
4275
|
+
source: parent.slotOwnerSource,
|
|
4276
|
+
field,
|
|
4277
|
+
identityMaterial: [...parent.slotOwnerMaterial, `slot:${field}`]
|
|
4278
|
+
}, origins, /* @__PURE__ */ new WeakSet());
|
|
4279
|
+
});
|
|
4280
|
+
return origins;
|
|
4281
|
+
}
|
|
4282
|
+
function childContextFor(entry, context, path) {
|
|
4283
|
+
if (entry.invalidExtraContext) {
|
|
4284
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4285
|
+
code: "E_COMPOSITION_INVALID_MOUNT",
|
|
4286
|
+
title: "mount received invalid source context",
|
|
4287
|
+
path,
|
|
4288
|
+
message: "A Bound Source cannot receive additional Source Context."
|
|
4289
|
+
}));
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
if (entry.contextProvider === void 0) return { present: false };
|
|
4293
|
+
if (typeof entry.contextProvider !== "function") return {
|
|
4294
|
+
present: true,
|
|
4295
|
+
value: entry.contextProvider
|
|
4296
|
+
};
|
|
4297
|
+
try {
|
|
4298
|
+
const value = context.context.present ? entry.contextProvider(context.context.value) : entry.contextProvider();
|
|
4299
|
+
if (isPromiseLike(value)) {
|
|
4300
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4301
|
+
code: "E_COMPOSITION_CONTEXT_MAPPER_ASYNC",
|
|
4302
|
+
title: "source context mapper returned a Promise",
|
|
4303
|
+
path,
|
|
4304
|
+
message: "Source Context Mappers must be synchronous in v0.3."
|
|
4305
|
+
}));
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4308
|
+
return {
|
|
4309
|
+
present: true,
|
|
4310
|
+
value
|
|
4311
|
+
};
|
|
4312
|
+
} catch (error) {
|
|
4313
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4314
|
+
code: "E_COMPOSITION_CONTEXT_MAPPER_FAILED",
|
|
4315
|
+
title: "source context mapper failed",
|
|
4316
|
+
path,
|
|
4317
|
+
message: error instanceof Error ? error.message : "Source Context Mapper threw."
|
|
4318
|
+
}));
|
|
4319
|
+
return;
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
function resolveSource(source, context) {
|
|
4323
|
+
const sourceState = source[COMPOSITION_SOURCE]();
|
|
4324
|
+
const effectiveContext = context.context.present ? context.context : sourceState.boundContext;
|
|
4325
|
+
if (context.depth > MAX_COMPOSITION_DEPTH) {
|
|
4326
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4327
|
+
code: "E_COMPOSITION_DEPTH_EXCEEDED",
|
|
4328
|
+
title: "composition depth exceeded",
|
|
4329
|
+
path: context.sourcePath,
|
|
4330
|
+
message: `Composition depth exceeded ${MAX_COMPOSITION_DEPTH}.`
|
|
4331
|
+
}));
|
|
4332
|
+
return;
|
|
4333
|
+
}
|
|
4334
|
+
if (context.stack.indexOf(sourceState.cycleId) !== -1) {
|
|
4335
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4336
|
+
code: "E_COMPOSITION_CYCLE",
|
|
4337
|
+
title: "composition cycle detected",
|
|
4338
|
+
path: context.sourcePath,
|
|
4339
|
+
message: "A Deck cannot mount itself through its descendant sources."
|
|
4340
|
+
}));
|
|
4341
|
+
return;
|
|
4342
|
+
}
|
|
4343
|
+
const entries = [];
|
|
4344
|
+
let slideCount = 0;
|
|
4345
|
+
const sourceKeys = /* @__PURE__ */ new Set();
|
|
4346
|
+
const slotOrigins = collectSourceSlots(effectiveContext, context);
|
|
4347
|
+
const nextContextBase = {
|
|
4348
|
+
diagnostics: context.diagnostics,
|
|
4349
|
+
stack: [...context.stack, sourceState.cycleId],
|
|
4350
|
+
depth: context.depth + 1
|
|
4351
|
+
};
|
|
4352
|
+
sourceState.entries.forEach((entry, index) => {
|
|
4353
|
+
if (entry.kind === "slide") {
|
|
4354
|
+
entries.push({
|
|
4355
|
+
kind: "slide",
|
|
4356
|
+
factory: entry.factory,
|
|
4357
|
+
path: `${context.sourcePath} > slideFactory[${index}]`
|
|
4358
|
+
});
|
|
4359
|
+
slideCount += 1;
|
|
4360
|
+
return;
|
|
4361
|
+
}
|
|
4362
|
+
const mountPath = `${context.sourcePath} > mount[${entry.sourceKey}]`;
|
|
4363
|
+
const invalidKey = validateSourceKey(entry.sourceKey);
|
|
4364
|
+
if (invalidKey) {
|
|
4365
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4366
|
+
code: "E_COMPOSITION_INVALID_SOURCE_KEY",
|
|
4367
|
+
title: "invalid source key",
|
|
4368
|
+
path: mountPath,
|
|
4369
|
+
message: invalidKey
|
|
4370
|
+
}));
|
|
4371
|
+
return;
|
|
4372
|
+
}
|
|
4373
|
+
if (sourceKeys.has(entry.sourceKey)) {
|
|
4374
|
+
addDiagnostic$1(context, compositionDiagnostic({
|
|
4375
|
+
code: "E_COMPOSITION_DUPLICATE_SOURCE_KEY",
|
|
4376
|
+
title: "duplicate source key",
|
|
4377
|
+
path: mountPath,
|
|
4378
|
+
message: `Source Key "${entry.sourceKey}" is already used in this parent source.`
|
|
4379
|
+
}));
|
|
4380
|
+
return;
|
|
4381
|
+
}
|
|
4382
|
+
sourceKeys.add(entry.sourceKey);
|
|
4383
|
+
const childContext = childContextFor(entry, context, mountPath);
|
|
4384
|
+
if (!childContext) return;
|
|
4385
|
+
const childSource = sourceOriginFor(context.source, entry.sourceKey);
|
|
4386
|
+
const childPlan = resolveSource(entry.source, {
|
|
4387
|
+
...nextContextBase,
|
|
4388
|
+
source: childSource,
|
|
4389
|
+
sourceIdentityMaterial: sourceMaterialFor(childSource),
|
|
4390
|
+
sourcePath: sourcePathFor(context.sourcePath, entry.sourceKey),
|
|
4391
|
+
context: childContext,
|
|
4392
|
+
slotOwnerSource: context.source,
|
|
4393
|
+
slotOwnerMaterial: context.sourceIdentityMaterial
|
|
4394
|
+
});
|
|
4395
|
+
if (!childPlan) return;
|
|
4396
|
+
entries.push({
|
|
4397
|
+
kind: "source",
|
|
4398
|
+
source: childPlan
|
|
4399
|
+
});
|
|
4400
|
+
slideCount += childPlan.slideCount;
|
|
4401
|
+
});
|
|
4402
|
+
return {
|
|
4403
|
+
source: context.source,
|
|
4404
|
+
sourceIdentityMaterial: context.sourceIdentityMaterial,
|
|
4405
|
+
context: effectiveContext,
|
|
4406
|
+
entries,
|
|
4407
|
+
slideCount,
|
|
4408
|
+
slotOrigins
|
|
4409
|
+
};
|
|
4410
|
+
}
|
|
4411
|
+
function flattenPlan(plan, deckTotalSlides, deckSlideIndex, roots, diagnostics) {
|
|
4412
|
+
let sourceSlideIndex = 0;
|
|
4413
|
+
let nextDeckSlideIndex = deckSlideIndex;
|
|
4414
|
+
for (const entry of plan.entries) {
|
|
4415
|
+
if (entry.kind === "source") {
|
|
4416
|
+
nextDeckSlideIndex = flattenPlan(entry.source, deckTotalSlides, nextDeckSlideIndex, roots, diagnostics);
|
|
4417
|
+
sourceSlideIndex += entry.source.slideCount;
|
|
4418
|
+
continue;
|
|
4419
|
+
}
|
|
4420
|
+
const composition = {
|
|
4421
|
+
...plan.source.kind === "mounted" ? { sourceKey: plan.source.sourceKey } : {},
|
|
4422
|
+
slideIndex: sourceSlideIndex,
|
|
4423
|
+
totalSlides: plan.slideCount,
|
|
4424
|
+
deckSlideIndex: nextDeckSlideIndex,
|
|
4425
|
+
deckTotalSlides
|
|
4426
|
+
};
|
|
4427
|
+
const input = plan.context.present ? {
|
|
4428
|
+
context: plan.context.value,
|
|
4429
|
+
composition
|
|
4430
|
+
} : { composition };
|
|
4431
|
+
const root = entry.factory(input);
|
|
4432
|
+
if (!isAuthorTreeNode(root) || !isSlideRoot(root)) diagnostics.push(compositionDiagnostic({
|
|
4433
|
+
code: "E_COMPOSITION_INVALID_ROOT",
|
|
4434
|
+
title: "slide factory must return a <Slide /> root",
|
|
4435
|
+
path: entry.path,
|
|
4436
|
+
message: describeInvalidRoot(root),
|
|
4437
|
+
help: ["Return <Slide>...</Slide> from the slide factory passed to deck.add()."]
|
|
4438
|
+
}));
|
|
4439
|
+
else roots.push({
|
|
4440
|
+
root,
|
|
4441
|
+
source: plan.source,
|
|
4442
|
+
sourceIdentityMaterial: plan.sourceIdentityMaterial,
|
|
4443
|
+
path: entry.path,
|
|
4444
|
+
composition,
|
|
4445
|
+
slotOrigins: plan.slotOrigins
|
|
4446
|
+
});
|
|
4447
|
+
sourceSlideIndex += 1;
|
|
4448
|
+
nextDeckSlideIndex += 1;
|
|
4449
|
+
}
|
|
4450
|
+
return nextDeckSlideIndex;
|
|
4451
|
+
}
|
|
4452
|
+
function resolveComposition(source) {
|
|
4453
|
+
const diagnostics = [];
|
|
4454
|
+
const rootPlan = resolveSource(source, {
|
|
4455
|
+
diagnostics,
|
|
4456
|
+
stack: [],
|
|
4457
|
+
depth: 0,
|
|
4458
|
+
source: ROOT_SOURCE,
|
|
4459
|
+
sourceIdentityMaterial: sourceMaterialFor(ROOT_SOURCE),
|
|
4460
|
+
sourcePath: "root",
|
|
4461
|
+
context: { present: false },
|
|
4462
|
+
slotOwnerSource: ROOT_SOURCE,
|
|
4463
|
+
slotOwnerMaterial: sourceMaterialFor(ROOT_SOURCE)
|
|
4464
|
+
});
|
|
4465
|
+
if (!rootPlan) return { diagnostics: createDiagnostics(diagnostics) };
|
|
4466
|
+
const roots = [];
|
|
4467
|
+
flattenPlan(rootPlan, rootPlan.slideCount, 0, roots, diagnostics);
|
|
4468
|
+
const resolvedDiagnostics = createDiagnostics(diagnostics);
|
|
4469
|
+
return {
|
|
4470
|
+
...resolvedDiagnostics.hasErrors ? {} : { roots },
|
|
4471
|
+
diagnostics: resolvedDiagnostics
|
|
4472
|
+
};
|
|
4473
|
+
}
|
|
4474
|
+
//#endregion
|
|
4475
|
+
//#region src/graph/identity.ts
|
|
4476
|
+
function slug(value) {
|
|
4477
|
+
return value.replace(/[^a-zA-Z0-9:_-]+/g, "_");
|
|
4478
|
+
}
|
|
4479
|
+
function graphNodeId(material) {
|
|
4480
|
+
return slug(material.join("/"));
|
|
4481
|
+
}
|
|
4482
|
+
function styleEntityId(material) {
|
|
4483
|
+
return slug(`style/${material.join("/")}`);
|
|
4484
|
+
}
|
|
4485
|
+
function assetEntityId(material) {
|
|
4486
|
+
return slug(`asset/${material.join("/")}`);
|
|
4487
|
+
}
|
|
4488
|
+
//#endregion
|
|
4489
|
+
//#region src/graph/roles.ts
|
|
4490
|
+
function semanticKindForTag(tag) {
|
|
4491
|
+
if (tag === "img") return "image";
|
|
4492
|
+
if (tag === "p" || tag.startsWith("h") || tag === "span") return tag === "span" ? "textRun" : "text";
|
|
4493
|
+
return "container";
|
|
4494
|
+
}
|
|
4495
|
+
function semanticKindForComponent(component) {
|
|
4496
|
+
switch (component) {
|
|
4497
|
+
case "Slide": return "slide";
|
|
4498
|
+
case "View": return "container";
|
|
4499
|
+
case "Text": return "text";
|
|
4500
|
+
case "Image": return "image";
|
|
4501
|
+
case "Shape": return "shape";
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
function semanticRoleForTag(tag) {
|
|
4505
|
+
switch (tag) {
|
|
4506
|
+
case "article":
|
|
4507
|
+
case "aside":
|
|
4508
|
+
case "footer":
|
|
4509
|
+
case "header":
|
|
4510
|
+
case "main":
|
|
4511
|
+
case "nav":
|
|
4512
|
+
case "section": return {
|
|
4513
|
+
kind: "sectioning",
|
|
4514
|
+
tag
|
|
4515
|
+
};
|
|
4516
|
+
case "div": return { kind: "genericContainer" };
|
|
4517
|
+
case "figure": return { kind: "figure" };
|
|
4518
|
+
case "p": return { kind: "paragraph" };
|
|
4519
|
+
case "h1":
|
|
4520
|
+
case "h2":
|
|
4521
|
+
case "h3":
|
|
4522
|
+
case "h4":
|
|
4523
|
+
case "h5":
|
|
4524
|
+
case "h6": return {
|
|
4525
|
+
kind: "heading",
|
|
4526
|
+
level: Number(tag.slice(1))
|
|
4527
|
+
};
|
|
4528
|
+
case "img": return { kind: "image" };
|
|
4529
|
+
case "span": return;
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
function semanticRoleForComponent(component) {
|
|
4533
|
+
switch (component) {
|
|
4534
|
+
case "Slide": return { kind: "slide" };
|
|
4535
|
+
case "Image": return { kind: "image" };
|
|
4536
|
+
case "Shape": return { kind: "shape" };
|
|
4537
|
+
case "Text":
|
|
4538
|
+
case "View": return;
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
//#endregion
|
|
4542
|
+
//#region src/graph/build.ts
|
|
4543
|
+
function keySegment(key, index) {
|
|
4544
|
+
return key === void 0 ? `index:${index}` : `key:${String(key)}`;
|
|
4545
|
+
}
|
|
4546
|
+
function sourceName(node) {
|
|
4547
|
+
return node.source.kind === "tag" ? node.source.tag : node.source.component;
|
|
4548
|
+
}
|
|
4549
|
+
function nodeSemanticKind(node) {
|
|
4550
|
+
return node.source.kind === "tag" ? semanticKindForTag(node.source.tag) : semanticKindForComponent(node.source.component);
|
|
4551
|
+
}
|
|
4552
|
+
function nodeRole(node) {
|
|
4553
|
+
return node.source.kind === "tag" ? semanticRoleForTag(node.source.tag) : semanticRoleForComponent(node.source.component);
|
|
4554
|
+
}
|
|
4555
|
+
function sourceFor(context) {
|
|
4556
|
+
return context.activeSlot?.source ?? context.source;
|
|
4557
|
+
}
|
|
4558
|
+
function contextForNode(node, context) {
|
|
4559
|
+
const slot = context.slotOrigins.get(node);
|
|
4560
|
+
if (!slot) return context;
|
|
4561
|
+
return {
|
|
4562
|
+
...context,
|
|
4563
|
+
activeSlot: slot,
|
|
4564
|
+
parentMaterial: [...context.parentMaterial, ...slot.identityMaterial],
|
|
4565
|
+
path: `${context.path} > slot[${slot.field}]`
|
|
4566
|
+
};
|
|
4567
|
+
}
|
|
4568
|
+
function originFor(node, path, context) {
|
|
4569
|
+
return {
|
|
4570
|
+
kind: "authored",
|
|
4571
|
+
path,
|
|
4572
|
+
source: sourceFor(context),
|
|
4573
|
+
...node.sourceSpan ? { sourceSpan: node.sourceSpan } : {}
|
|
4574
|
+
};
|
|
4575
|
+
}
|
|
4576
|
+
function textOriginFor(node, path, context) {
|
|
4577
|
+
return {
|
|
4578
|
+
kind: "authored",
|
|
4579
|
+
path,
|
|
4580
|
+
source: sourceFor(context),
|
|
4581
|
+
...node.sourceSpan ? { sourceSpan: node.sourceSpan } : {}
|
|
4582
|
+
};
|
|
4583
|
+
}
|
|
4584
|
+
function propsWithoutStyle(props) {
|
|
4585
|
+
const { style: _style, children: _children, ...direct } = props;
|
|
4586
|
+
return Object.keys(direct).length === 0 ? void 0 : direct;
|
|
4587
|
+
}
|
|
4588
|
+
function styleRefFor(state, idMaterial, target, props) {
|
|
4589
|
+
const style = props.style;
|
|
4590
|
+
const direct = propsWithoutStyle(props);
|
|
4591
|
+
if (style === void 0 && direct === void 0) return;
|
|
4592
|
+
const id = styleEntityId(idMaterial);
|
|
4593
|
+
state.styles.set(id, {
|
|
4594
|
+
id,
|
|
4595
|
+
target,
|
|
4596
|
+
authored: {
|
|
4597
|
+
...style !== void 0 ? { style } : {},
|
|
4598
|
+
...direct !== void 0 ? { direct } : {}
|
|
4599
|
+
}
|
|
4600
|
+
});
|
|
4601
|
+
return id;
|
|
4602
|
+
}
|
|
4603
|
+
function addDiagnostic(state, item) {
|
|
4604
|
+
state.diagnostics.push(item);
|
|
4605
|
+
}
|
|
4606
|
+
function invalidStructure(path, title, message, help) {
|
|
4607
|
+
return diagnostic({
|
|
4608
|
+
severity: "error",
|
|
4609
|
+
code: "E_SEMANTIC_STRUCTURE",
|
|
4610
|
+
title,
|
|
4611
|
+
labels: [{
|
|
4612
|
+
path,
|
|
4613
|
+
message
|
|
4614
|
+
}],
|
|
4615
|
+
...message ? { message } : {},
|
|
4616
|
+
...help ? { help } : {}
|
|
4617
|
+
});
|
|
4618
|
+
}
|
|
4619
|
+
function assetForImage(state, idMaterial, props, path) {
|
|
4620
|
+
if (typeof props.src !== "string" && typeof props.data !== "string") {
|
|
4621
|
+
addDiagnostic(state, invalidStructure(path, "image source is missing", "Image nodes require either src or data.", ["Add a src path or data URL to the image."]));
|
|
4622
|
+
return;
|
|
4623
|
+
}
|
|
4624
|
+
const id = assetEntityId(idMaterial);
|
|
4625
|
+
const entity = {
|
|
4626
|
+
id,
|
|
4627
|
+
kind: "image",
|
|
4628
|
+
source: typeof props.src === "string" ? {
|
|
4629
|
+
kind: "path",
|
|
4630
|
+
path: props.src
|
|
4631
|
+
} : {
|
|
4632
|
+
kind: "data",
|
|
4633
|
+
data: props.data
|
|
4634
|
+
},
|
|
4635
|
+
metadata: typeof props.data === "string" && props.data.startsWith("data:") ? { mediaType: props.data.slice(5, props.data.indexOf(";")) || void 0 } : {},
|
|
4636
|
+
resolution: "unresolved"
|
|
4637
|
+
};
|
|
4638
|
+
state.assets.set(id, entity);
|
|
4639
|
+
return id;
|
|
4640
|
+
}
|
|
4641
|
+
function semanticBase(state, node, id, kind, path, material, context) {
|
|
4642
|
+
const styleRef = styleRefFor(state, material, kind, node.props);
|
|
4643
|
+
return {
|
|
4644
|
+
id,
|
|
4645
|
+
kind,
|
|
4646
|
+
origin: originFor(node, path, context),
|
|
4647
|
+
...node.source.kind === "tag" ? { authoredTag: node.source.tag } : {},
|
|
4648
|
+
...node.source.kind === "component" ? { authoredComponent: node.source.component } : {},
|
|
4649
|
+
...node.key !== void 0 ? { key: node.key } : {},
|
|
4650
|
+
...nodeRole(node) ? { role: nodeRole(node) } : {},
|
|
4651
|
+
...styleRef ? { styleRef } : {}
|
|
4652
|
+
};
|
|
4653
|
+
}
|
|
4654
|
+
function buildTextRunFromLeaf(state, leaf, context, index) {
|
|
4655
|
+
const text = typeof leaf.value === "string" ? leaf.value : String(leaf.value);
|
|
4656
|
+
if (text.trim().length === 0) return;
|
|
4657
|
+
const segment = `text:${index}`;
|
|
4658
|
+
const id = graphNodeId([...context.parentMaterial, segment]);
|
|
4659
|
+
const path = `${context.path} > text[${index}]`;
|
|
4660
|
+
state.nodes.set(id, {
|
|
4661
|
+
id,
|
|
4662
|
+
kind: "textRun",
|
|
4663
|
+
origin: textOriginFor(leaf, path, context),
|
|
4664
|
+
text
|
|
4665
|
+
});
|
|
4666
|
+
return {
|
|
4667
|
+
id,
|
|
4668
|
+
kind: "textRun"
|
|
4669
|
+
};
|
|
4670
|
+
}
|
|
4671
|
+
function buildImplicitTextNode(state, leaf, context, index) {
|
|
4672
|
+
const run = buildTextRunFromLeaf(state, leaf, {
|
|
4673
|
+
...context,
|
|
4674
|
+
parentMaterial: [...context.parentMaterial, `implicit-text:${index}`],
|
|
4675
|
+
path: `${context.path} > implicitText[${index}]`
|
|
4676
|
+
}, 0);
|
|
4677
|
+
if (!run) return;
|
|
4678
|
+
const id = graphNodeId([...context.parentMaterial, `implicit-text:${index}`]);
|
|
4679
|
+
state.nodes.set(id, {
|
|
4680
|
+
id,
|
|
4681
|
+
kind: "text",
|
|
4682
|
+
origin: {
|
|
4683
|
+
kind: "implicit",
|
|
4684
|
+
path: `${context.path} > implicitText[${index}]`,
|
|
4685
|
+
source: sourceFor(context),
|
|
4686
|
+
...leaf.sourceSpan ? { sourceSpan: leaf.sourceSpan } : {},
|
|
4687
|
+
reason: "primitive-text-in-container"
|
|
4688
|
+
},
|
|
4689
|
+
implicit: true,
|
|
4690
|
+
inlineChildren: [run.id]
|
|
4691
|
+
});
|
|
4692
|
+
return {
|
|
4693
|
+
id,
|
|
4694
|
+
kind: "text"
|
|
4695
|
+
};
|
|
4696
|
+
}
|
|
4697
|
+
function buildChildren(state, children, context) {
|
|
4698
|
+
const ids = [];
|
|
4699
|
+
children.forEach((child, index) => {
|
|
4700
|
+
if (child.kind === "fragment") {
|
|
4701
|
+
const childContext = contextForNode(child, context);
|
|
4702
|
+
const segment = `fragment:${keySegment(child.key, index)}`;
|
|
4703
|
+
ids.push(...buildChildren(state, child.children, {
|
|
4704
|
+
...childContext,
|
|
4705
|
+
parentMaterial: [...childContext.parentMaterial, segment],
|
|
4706
|
+
path: `${childContext.path} > fragment[${keySegment(child.key, index)}]`
|
|
4707
|
+
}));
|
|
4708
|
+
return;
|
|
4709
|
+
}
|
|
4710
|
+
const built = buildNode(state, child, context, index);
|
|
4711
|
+
if (built) ids.push(built.id);
|
|
4712
|
+
});
|
|
4713
|
+
return ids;
|
|
4714
|
+
}
|
|
4715
|
+
function buildTextLikeNode(state, node, id, path, material, context) {
|
|
4716
|
+
const inlineChildren = [];
|
|
4717
|
+
node.children.forEach((child, index) => {
|
|
4718
|
+
if (child.kind === "text") {
|
|
4719
|
+
const run = buildTextRunFromLeaf(state, child, {
|
|
4720
|
+
...context,
|
|
4721
|
+
parentId: id,
|
|
4722
|
+
parentMaterial: material,
|
|
4723
|
+
path,
|
|
4724
|
+
inline: true
|
|
4725
|
+
}, index);
|
|
4726
|
+
if (run) inlineChildren.push(run.id);
|
|
4727
|
+
return;
|
|
4728
|
+
}
|
|
4729
|
+
if (child.kind === "fragment") {
|
|
4730
|
+
const childContext = contextForNode(child, {
|
|
4731
|
+
...context,
|
|
4732
|
+
parentId: id,
|
|
4733
|
+
parentMaterial: material,
|
|
4734
|
+
path,
|
|
4735
|
+
inline: true
|
|
4736
|
+
});
|
|
4737
|
+
const segment = `fragment:${keySegment(child.key, index)}`;
|
|
4738
|
+
inlineChildren.push(...buildChildren(state, child.children, {
|
|
4739
|
+
...childContext,
|
|
4740
|
+
parentMaterial: [...childContext.parentMaterial, segment],
|
|
4741
|
+
path: `${childContext.path} > fragment[${keySegment(child.key, index)}]`
|
|
4742
|
+
}));
|
|
4743
|
+
return;
|
|
4744
|
+
}
|
|
4745
|
+
if (child.source.kind === "tag" && child.source.tag === "span") {
|
|
4746
|
+
const built = buildNode(state, child, {
|
|
4747
|
+
...context,
|
|
4748
|
+
parentId: id,
|
|
4749
|
+
parentMaterial: material,
|
|
4750
|
+
path,
|
|
4751
|
+
inline: true
|
|
4752
|
+
}, index);
|
|
4753
|
+
if (built) inlineChildren.push(built.id);
|
|
4754
|
+
return;
|
|
4755
|
+
}
|
|
4756
|
+
addDiagnostic(state, invalidStructure(`${path} > ${sourceName(child)}[${index}]`, "block content cannot appear inside text", "Text-like elements accept primitive text and inline spans only."));
|
|
4757
|
+
});
|
|
4758
|
+
state.nodes.set(id, {
|
|
4759
|
+
...semanticBase(state, node, id, "text", path, material, context),
|
|
4760
|
+
kind: "text",
|
|
4761
|
+
inlineChildren
|
|
4762
|
+
});
|
|
4763
|
+
return {
|
|
4764
|
+
id,
|
|
4765
|
+
kind: "text"
|
|
4766
|
+
};
|
|
4767
|
+
}
|
|
4768
|
+
function collectInlineText(state, children, path) {
|
|
4769
|
+
let text = "";
|
|
4770
|
+
children.forEach((child, index) => {
|
|
4771
|
+
if (child.kind === "text") {
|
|
4772
|
+
text += typeof child.value === "string" ? child.value : String(child.value);
|
|
4773
|
+
return;
|
|
4774
|
+
}
|
|
4775
|
+
if (child.kind === "fragment") {
|
|
4776
|
+
text += collectInlineText(state, child.children, `${path} > fragment[${keySegment(child.key, index)}]`);
|
|
4777
|
+
return;
|
|
4778
|
+
}
|
|
4779
|
+
if (child.source.kind === "tag" && child.source.tag === "span") {
|
|
4780
|
+
text += collectInlineText(state, child.children, `${path} > span[${keySegment(child.key, index)}]`);
|
|
4781
|
+
return;
|
|
4782
|
+
}
|
|
4783
|
+
addDiagnostic(state, invalidStructure(`${path} > ${sourceName(child)}[${index}]`, "block content cannot appear inside span", "span accepts primitive text or nested inline spans only."));
|
|
4784
|
+
});
|
|
4785
|
+
return text;
|
|
4786
|
+
}
|
|
4787
|
+
function buildNode(state, node, context, index) {
|
|
4788
|
+
const nodeContext = contextForNode(node, context);
|
|
4789
|
+
if (node.kind === "fragment") return;
|
|
4790
|
+
if (node.kind === "text") return nodeContext.inline ? buildTextRunFromLeaf(state, node, nodeContext, index) : buildImplicitTextNode(state, node, nodeContext, index);
|
|
4791
|
+
const kind = nodeSemanticKind(node);
|
|
4792
|
+
const segment = `${sourceName(node)}:${keySegment(node.key, index)}`;
|
|
4793
|
+
const material = [...nodeContext.parentMaterial, segment];
|
|
4794
|
+
const id = graphNodeId(material);
|
|
4795
|
+
const path = `${nodeContext.path} > ${sourceName(node)}[${keySegment(node.key, index)}]`;
|
|
4796
|
+
if (kind === "textRun") {
|
|
4797
|
+
if (!context.inline) {
|
|
4798
|
+
addDiagnostic(state, invalidStructure(path, "span cannot appear here", "span must be inside a text-like element.", ["Wrap the span in <p>...</p> or move it inside an existing text element."]));
|
|
4799
|
+
return;
|
|
4800
|
+
}
|
|
4801
|
+
const text = collectInlineText(state, node.children, path);
|
|
4802
|
+
state.nodes.set(id, {
|
|
4803
|
+
...semanticBase(state, node, id, "textRun", path, material, nodeContext),
|
|
4804
|
+
kind: "textRun",
|
|
4805
|
+
text
|
|
4806
|
+
});
|
|
4807
|
+
return {
|
|
4808
|
+
id,
|
|
4809
|
+
kind: "textRun"
|
|
4810
|
+
};
|
|
4811
|
+
}
|
|
4812
|
+
if (kind === "text") return buildTextLikeNode(state, node, id, path, material, nodeContext);
|
|
4813
|
+
if (kind === "image") {
|
|
4814
|
+
if (node.children.length > 0) addDiagnostic(state, invalidStructure(path, "image cannot have children", "Image nodes are leaf nodes."));
|
|
4815
|
+
const assetRef = assetForImage(state, material, node.props, path);
|
|
4816
|
+
state.nodes.set(id, {
|
|
4817
|
+
...semanticBase(state, node, id, "image", path, material, nodeContext),
|
|
4818
|
+
kind: "image",
|
|
4819
|
+
...assetRef ? { assetRef } : {}
|
|
4820
|
+
});
|
|
4821
|
+
return {
|
|
4822
|
+
id,
|
|
4823
|
+
kind: "image"
|
|
4824
|
+
};
|
|
4825
|
+
}
|
|
4826
|
+
const childIds = buildChildren(state, node.children, {
|
|
4827
|
+
parentId: id,
|
|
4828
|
+
parentMaterial: material,
|
|
4829
|
+
path,
|
|
4830
|
+
inline: false,
|
|
4831
|
+
source: sourceFor(nodeContext),
|
|
4832
|
+
slotOrigins: nodeContext.slotOrigins,
|
|
4833
|
+
activeSlot: nodeContext.activeSlot
|
|
4834
|
+
});
|
|
4835
|
+
state.nodes.set(id, {
|
|
4836
|
+
...semanticBase(state, node, id, kind, path, material, nodeContext),
|
|
4837
|
+
kind,
|
|
4838
|
+
children: childIds
|
|
4839
|
+
});
|
|
4840
|
+
return {
|
|
4841
|
+
id,
|
|
4842
|
+
kind
|
|
4843
|
+
};
|
|
4844
|
+
}
|
|
4845
|
+
function rootSource() {
|
|
4846
|
+
return { kind: "root" };
|
|
4847
|
+
}
|
|
4848
|
+
function asComposedRoot(root, index) {
|
|
4849
|
+
if (root.kind !== "element") throw new Error("Semantic graph roots must be element nodes.");
|
|
4850
|
+
return {
|
|
4851
|
+
root,
|
|
4852
|
+
source: rootSource(),
|
|
4853
|
+
sourceIdentityMaterial: ["source", "root"],
|
|
4854
|
+
path: `document > slideFactory[${index}]`,
|
|
4855
|
+
composition: {
|
|
4856
|
+
slideIndex: index,
|
|
4857
|
+
totalSlides: 0,
|
|
4858
|
+
deckSlideIndex: index,
|
|
4859
|
+
deckTotalSlides: 0
|
|
4860
|
+
},
|
|
4861
|
+
slotOrigins: /* @__PURE__ */ new WeakMap()
|
|
4862
|
+
};
|
|
4863
|
+
}
|
|
4864
|
+
function buildSemanticAuthorGraph(roots) {
|
|
4865
|
+
const documentId = graphNodeId(["document", "root"]);
|
|
4866
|
+
const state = {
|
|
4867
|
+
nodes: /* @__PURE__ */ new Map(),
|
|
4868
|
+
styles: /* @__PURE__ */ new Map(),
|
|
4869
|
+
assets: /* @__PURE__ */ new Map(),
|
|
4870
|
+
diagnostics: []
|
|
4871
|
+
};
|
|
4872
|
+
const slideIds = [];
|
|
4873
|
+
roots.forEach((root, index) => {
|
|
4874
|
+
const composed = "root" in root ? root : asComposedRoot(root, index);
|
|
4875
|
+
const built = buildNode(state, composed.root, {
|
|
4876
|
+
parentId: documentId,
|
|
4877
|
+
parentMaterial: [
|
|
4878
|
+
"document",
|
|
4879
|
+
"root",
|
|
4880
|
+
...composed.sourceIdentityMaterial
|
|
4881
|
+
],
|
|
4882
|
+
path: composed.path,
|
|
4883
|
+
inline: false,
|
|
4884
|
+
source: composed.source,
|
|
4885
|
+
slotOrigins: composed.slotOrigins
|
|
4886
|
+
}, composed.composition.slideIndex);
|
|
4887
|
+
if (built) slideIds.push(built.id);
|
|
4888
|
+
});
|
|
4889
|
+
const documentNode = {
|
|
4890
|
+
id: documentId,
|
|
4891
|
+
kind: "document",
|
|
4892
|
+
origin: {
|
|
4893
|
+
kind: "implicit",
|
|
4894
|
+
path: "document",
|
|
4895
|
+
source: rootSource()
|
|
4896
|
+
},
|
|
4897
|
+
role: { kind: "document" },
|
|
4898
|
+
children: slideIds
|
|
4899
|
+
};
|
|
4900
|
+
state.nodes.set(documentId, documentNode);
|
|
4901
|
+
const diagnostics = createDiagnostics(state.diagnostics);
|
|
4902
|
+
return {
|
|
4903
|
+
graph: {
|
|
4904
|
+
documentId,
|
|
4905
|
+
nodes: state.nodes,
|
|
4906
|
+
styles: state.styles,
|
|
4907
|
+
assets: state.assets
|
|
4908
|
+
},
|
|
4909
|
+
diagnostics
|
|
4112
4910
|
};
|
|
4113
4911
|
}
|
|
4114
4912
|
//#endregion
|
|
@@ -14974,6 +15772,24 @@ function toPptxTabStops(tabStops) {
|
|
|
14974
15772
|
...tabStop.alignment ? { alignment: tabStop.alignment } : {}
|
|
14975
15773
|
}));
|
|
14976
15774
|
}
|
|
15775
|
+
function toPptxTextRunOptions(style) {
|
|
15776
|
+
if (!style) return;
|
|
15777
|
+
const options = {
|
|
15778
|
+
fontFace: style.fontFamily,
|
|
15779
|
+
fontSize: style.fontSizePt,
|
|
15780
|
+
color: style.color,
|
|
15781
|
+
bold: style.fontWeight === "bold" || typeof style.fontWeight === "number" && style.fontWeight >= 600,
|
|
15782
|
+
italic: style.italic,
|
|
15783
|
+
underline: toPptxUnderline(style),
|
|
15784
|
+
strike: style.strike,
|
|
15785
|
+
charSpacing: style.charSpacing,
|
|
15786
|
+
superscript: style.superscript,
|
|
15787
|
+
subscript: style.subscript,
|
|
15788
|
+
breakLine: false
|
|
15789
|
+
};
|
|
15790
|
+
if (Object.values(options).every((value) => value === void 0 || value === false)) return;
|
|
15791
|
+
return options;
|
|
15792
|
+
}
|
|
14977
15793
|
function emitOutlineShape(slide, shapeName, frame, outline, radiusEmu, effectiveOpacity, rotation, flipH, flipV) {
|
|
14978
15794
|
if (!outline) return;
|
|
14979
15795
|
const insetEmu = pointsToEmu(outline.widthPt) / 2;
|
|
@@ -15048,7 +15864,14 @@ function emitText(slide, node, inheritedOpacity) {
|
|
|
15048
15864
|
emitOutlineShape(slide, node.radiusEmu && node.radiusEmu > 0 ? "roundRect" : "rect", node.frame, node.outline, node.radiusEmu, effectiveOpacity, node.rotation, node.flipH, node.flipV);
|
|
15049
15865
|
emitEdgeStrokes(slide, node.frame, node.edgeStrokes, effectiveOpacity, node.rotation, node.flipH, node.flipV);
|
|
15050
15866
|
emitBackgroundLayers(slide, node.frame, node.backgroundLayers, node.radiusEmu && node.radiusEmu > 0 ? "roundRect" : "rect", node.radiusEmu, effectiveOpacity, node.rotation, node.flipH, node.flipV);
|
|
15051
|
-
|
|
15867
|
+
const textContent = node.content.runs ? node.content.runs.map((run) => {
|
|
15868
|
+
const options = toPptxTextRunOptions(run.style);
|
|
15869
|
+
return {
|
|
15870
|
+
text: run.text,
|
|
15871
|
+
...options ? { options } : {}
|
|
15872
|
+
};
|
|
15873
|
+
}) : node.content.text;
|
|
15874
|
+
slide.addText(textContent, {
|
|
15052
15875
|
x: emuToInches(node.frame.xEmu),
|
|
15053
15876
|
y: emuToInches(node.frame.yEmu),
|
|
15054
15877
|
w: emuToInches(node.frame.widthEmu),
|
|
@@ -15212,22 +16035,105 @@ async function outputPresentation(presentation, config) {
|
|
|
15212
16035
|
}
|
|
15213
16036
|
//#endregion
|
|
15214
16037
|
//#region src/deck.ts
|
|
16038
|
+
function hasMountedSources(entries) {
|
|
16039
|
+
return entries.some((entry) => entry.kind === "mount");
|
|
16040
|
+
}
|
|
16041
|
+
function directSlideFactories(entries) {
|
|
16042
|
+
return entries.flatMap((entry) => entry.kind === "slide" ? [entry.factory] : []);
|
|
16043
|
+
}
|
|
16044
|
+
function mountedSourceError() {
|
|
16045
|
+
return /* @__PURE__ */ new Error("Mounted sources are supported by compile() only until the output pipeline supports graph composition.");
|
|
16046
|
+
}
|
|
16047
|
+
function compileSource(source, config = {}) {
|
|
16048
|
+
const composition = resolveComposition(source);
|
|
16049
|
+
if (composition.diagnostics.hasErrors) {
|
|
16050
|
+
if (config.mode === "inspect") return { diagnostics: composition.diagnostics };
|
|
16051
|
+
throw new CompositionDiagnosticError(composition.diagnostics);
|
|
16052
|
+
}
|
|
16053
|
+
const result = buildSemanticAuthorGraph(composition.roots ?? []);
|
|
16054
|
+
if (config.mode === "inspect") return result;
|
|
16055
|
+
if (result.diagnostics.hasErrors) throw new SemanticGraphDiagnosticError(result.diagnostics);
|
|
16056
|
+
if (!result.graph) throw new SemanticGraphDiagnosticError(result.diagnostics);
|
|
16057
|
+
return result.graph;
|
|
16058
|
+
}
|
|
16059
|
+
var BoundSource = class {
|
|
16060
|
+
#source;
|
|
16061
|
+
#sourceContext;
|
|
16062
|
+
constructor(source, sourceContext) {
|
|
16063
|
+
this.#source = source;
|
|
16064
|
+
this.#sourceContext = sourceContext;
|
|
16065
|
+
}
|
|
16066
|
+
[COMPOSITION_SOURCE]() {
|
|
16067
|
+
const source = this.#source[COMPOSITION_SOURCE]();
|
|
16068
|
+
return {
|
|
16069
|
+
entries: source.entries,
|
|
16070
|
+
cycleId: source.cycleId,
|
|
16071
|
+
boundContext: {
|
|
16072
|
+
present: true,
|
|
16073
|
+
value: this.#sourceContext
|
|
16074
|
+
}
|
|
16075
|
+
};
|
|
16076
|
+
}
|
|
16077
|
+
compile(config = {}) {
|
|
16078
|
+
return compileSource(this, config);
|
|
16079
|
+
}
|
|
16080
|
+
render() {
|
|
16081
|
+
const source = this.#source[COMPOSITION_SOURCE]();
|
|
16082
|
+
if (hasMountedSources(source.entries)) throw mountedSourceError();
|
|
16083
|
+
return renderPresentation(this.#source.options, directSlideFactories(source.entries).map((factory) => (input) => factory({
|
|
16084
|
+
...input,
|
|
16085
|
+
context: this.#sourceContext
|
|
16086
|
+
})));
|
|
16087
|
+
}
|
|
16088
|
+
async output(config) {
|
|
16089
|
+
await outputPresentation(this.render(), config);
|
|
16090
|
+
}
|
|
16091
|
+
};
|
|
15215
16092
|
var Deck = class {
|
|
15216
16093
|
#options;
|
|
15217
|
-
#
|
|
16094
|
+
#entries = [];
|
|
16095
|
+
withSource;
|
|
15218
16096
|
constructor(options) {
|
|
15219
16097
|
this.#options = options;
|
|
16098
|
+
this.withSource = ((sourceContext) => new BoundSource(this, sourceContext));
|
|
16099
|
+
}
|
|
16100
|
+
get options() {
|
|
16101
|
+
return this.#options;
|
|
16102
|
+
}
|
|
16103
|
+
[COMPOSITION_SOURCE]() {
|
|
16104
|
+
return {
|
|
16105
|
+
entries: this.#entries,
|
|
16106
|
+
cycleId: this,
|
|
16107
|
+
boundContext: { present: false }
|
|
16108
|
+
};
|
|
15220
16109
|
}
|
|
15221
16110
|
add(slide) {
|
|
15222
|
-
this.#
|
|
16111
|
+
this.#entries.push({
|
|
16112
|
+
kind: "slide",
|
|
16113
|
+
factory: slide
|
|
16114
|
+
});
|
|
16115
|
+
return this;
|
|
16116
|
+
}
|
|
16117
|
+
mount(sourceKey, child, ...context) {
|
|
16118
|
+
this.#entries.push({
|
|
16119
|
+
kind: "mount",
|
|
16120
|
+
sourceKey,
|
|
16121
|
+
source: child,
|
|
16122
|
+
...context.length > 0 ? { contextProvider: context[0] } : {},
|
|
16123
|
+
...child instanceof BoundSource && context.length > 0 ? { invalidExtraContext: true } : {}
|
|
16124
|
+
});
|
|
15223
16125
|
return this;
|
|
15224
16126
|
}
|
|
15225
16127
|
render() {
|
|
15226
|
-
|
|
16128
|
+
if (hasMountedSources(this.#entries)) throw mountedSourceError();
|
|
16129
|
+
return renderPresentation(this.#options, directSlideFactories(this.#entries));
|
|
16130
|
+
}
|
|
16131
|
+
compile(config = {}) {
|
|
16132
|
+
return compileSource(this, config);
|
|
15227
16133
|
}
|
|
15228
16134
|
async output(config) {
|
|
15229
16135
|
await outputPresentation(this.render(), config);
|
|
15230
16136
|
}
|
|
15231
16137
|
};
|
|
15232
16138
|
//#endregion
|
|
15233
|
-
export { Deck, EMU_PER_INCH, Fragment, Image, POINTS_PER_INCH, Shape, Slide, Text, View, createElement, isAuthorNode, isContentNode, isSlideNode, pptxgenjsBackend };
|
|
16139
|
+
export { CompositionDiagnosticError, Deck, DeckDiagnosticError, EMU_PER_INCH, Fragment, Image, POINTS_PER_INCH, SemanticGraphDiagnosticError, Shape, Slide, Text, View, createElement, formatDiagnostic, formatDiagnostics, isAuthorNode, isContentNode, isSlideNode, pptxgenjsBackend };
|