epub-codec 0.0.0 → 1.0.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.
Files changed (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -0
  3. package/dist/codec.cjs +28 -0
  4. package/dist/codec.d.cts +2308 -0
  5. package/dist/codec.d.ts +2308 -0
  6. package/dist/codec.js +25 -0
  7. package/dist/diagnostics-Ee4kG7mw.d.cts +60 -0
  8. package/dist/diagnostics-Ee4kG7mw.d.ts +60 -0
  9. package/dist/diagnostics.cjs +96 -0
  10. package/dist/diagnostics.d.cts +2 -0
  11. package/dist/diagnostics.d.ts +2 -0
  12. package/dist/diagnostics.js +85 -0
  13. package/dist/format.cjs +9 -0
  14. package/dist/format.d.cts +6 -0
  15. package/dist/format.d.ts +6 -0
  16. package/dist/format.js +6 -0
  17. package/dist/image/dimensions.cjs +82 -0
  18. package/dist/image/dimensions.d.cts +11 -0
  19. package/dist/image/dimensions.d.ts +11 -0
  20. package/dist/image/dimensions.js +79 -0
  21. package/dist/index.cjs +105 -0
  22. package/dist/index.d.cts +32 -0
  23. package/dist/index.d.ts +32 -0
  24. package/dist/index.js +32 -0
  25. package/dist/nav/nav3.cjs +19 -0
  26. package/dist/nav/nav3.d.cts +4 -0
  27. package/dist/nav/nav3.d.ts +4 -0
  28. package/dist/nav/nav3.js +18 -0
  29. package/dist/nav/ncx.cjs +17 -0
  30. package/dist/nav/ncx.d.cts +4 -0
  31. package/dist/nav/ncx.d.ts +4 -0
  32. package/dist/nav/ncx.js +16 -0
  33. package/dist/nav/reconcile.cjs +8 -0
  34. package/dist/nav/reconcile.d.cts +4 -0
  35. package/dist/nav/reconcile.d.ts +4 -0
  36. package/dist/nav/reconcile.js +7 -0
  37. package/dist/nav/write.cjs +39 -0
  38. package/dist/nav/write.d.cts +10 -0
  39. package/dist/nav/write.d.ts +10 -0
  40. package/dist/nav/write.js +37 -0
  41. package/dist/ocf/container.cjs +20 -0
  42. package/dist/ocf/container.d.cts +4 -0
  43. package/dist/ocf/container.d.ts +4 -0
  44. package/dist/ocf/container.js +19 -0
  45. package/dist/ocf/write.cjs +13 -0
  46. package/dist/ocf/write.d.cts +4 -0
  47. package/dist/ocf/write.d.ts +4 -0
  48. package/dist/ocf/write.js +12 -0
  49. package/dist/opf/metadata.cjs +51 -0
  50. package/dist/opf/metadata.d.cts +7 -0
  51. package/dist/opf/metadata.d.ts +7 -0
  52. package/dist/opf/metadata.js +50 -0
  53. package/dist/opf/parse.cjs +47 -0
  54. package/dist/opf/parse.d.cts +6 -0
  55. package/dist/opf/parse.d.ts +6 -0
  56. package/dist/opf/parse.js +46 -0
  57. package/dist/opf/types.cjs +0 -0
  58. package/dist/opf/types.d.cts +20 -0
  59. package/dist/opf/types.d.ts +20 -0
  60. package/dist/opf/types.js +0 -0
  61. package/dist/opf/write.cjs +55 -0
  62. package/dist/opf/write.d.cts +12 -0
  63. package/dist/opf/write.d.ts +12 -0
  64. package/dist/opf/write.js +54 -0
  65. package/dist/path.cjs +22 -0
  66. package/dist/path.d.cts +5 -0
  67. package/dist/path.d.ts +5 -0
  68. package/dist/path.js +20 -0
  69. package/dist/read.cjs +166 -0
  70. package/dist/read.d.cts +10 -0
  71. package/dist/read.d.ts +10 -0
  72. package/dist/read.js +164 -0
  73. package/dist/util/base64.cjs +51 -0
  74. package/dist/util/base64.d.cts +5 -0
  75. package/dist/util/base64.d.ts +5 -0
  76. package/dist/util/base64.js +49 -0
  77. package/dist/write.cjs +136 -0
  78. package/dist/write.d.cts +10 -0
  79. package/dist/write.d.ts +10 -0
  80. package/dist/write.js +134 -0
  81. package/dist/xhtml/context.cjs +0 -0
  82. package/dist/xhtml/context.d.cts +20 -0
  83. package/dist/xhtml/context.d.ts +20 -0
  84. package/dist/xhtml/context.js +0 -0
  85. package/dist/xhtml/footnote.cjs +32 -0
  86. package/dist/xhtml/footnote.d.cts +7 -0
  87. package/dist/xhtml/footnote.d.ts +7 -0
  88. package/dist/xhtml/footnote.js +29 -0
  89. package/dist/xhtml/inline.cjs +128 -0
  90. package/dist/xhtml/inline.d.cts +11 -0
  91. package/dist/xhtml/inline.d.ts +11 -0
  92. package/dist/xhtml/inline.js +127 -0
  93. package/dist/xhtml/list-id.cjs +22 -0
  94. package/dist/xhtml/list-id.d.cts +13 -0
  95. package/dist/xhtml/list-id.d.ts +13 -0
  96. package/dist/xhtml/list-id.js +20 -0
  97. package/dist/xhtml/read.cjs +423 -0
  98. package/dist/xhtml/read.d.cts +20 -0
  99. package/dist/xhtml/read.d.ts +20 -0
  100. package/dist/xhtml/read.js +422 -0
  101. package/dist/xhtml/style-constants.cjs +13 -0
  102. package/dist/xhtml/style-constants.d.cts +8 -0
  103. package/dist/xhtml/style-constants.d.ts +8 -0
  104. package/dist/xhtml/style-constants.js +8 -0
  105. package/dist/xhtml/write.cjs +183 -0
  106. package/dist/xhtml/write.d.cts +12 -0
  107. package/dist/xhtml/write.d.ts +12 -0
  108. package/dist/xhtml/write.js +182 -0
  109. package/dist/xml/build.cjs +46 -0
  110. package/dist/xml/build.d.cts +5 -0
  111. package/dist/xml/build.d.ts +5 -0
  112. package/dist/xml/build.js +46 -0
  113. package/dist/xml/entities.cjs +20 -0
  114. package/dist/xml/entities.d.cts +5 -0
  115. package/dist/xml/entities.d.ts +5 -0
  116. package/dist/xml/entities.js +18 -0
  117. package/dist/xml/node.cjs +67 -0
  118. package/dist/xml/node.d.cts +83 -0
  119. package/dist/xml/node.d.ts +83 -0
  120. package/dist/xml/node.js +58 -0
  121. package/dist/xml/parse.cjs +88 -0
  122. package/dist/xml/parse.d.cts +5 -0
  123. package/dist/xml/parse.d.ts +5 -0
  124. package/dist/xml/parse.js +88 -0
  125. package/dist/xml/query.cjs +44 -0
  126. package/dist/xml/query.d.cts +11 -0
  127. package/dist/xml/query.d.ts +11 -0
  128. package/dist/xml/query.js +37 -0
  129. package/dist/zip.cjs +19 -0
  130. package/dist/zip.d.cts +9 -0
  131. package/dist/zip.d.ts +9 -0
  132. package/dist/zip.js +17 -0
  133. package/package.json +95 -2
@@ -0,0 +1,422 @@
1
+ import { EpubDiagnosticCodes } from "../diagnostics.js";
2
+ import { attrValue, elementsWithTag, findChildElement, rootElement, textContent } from "../xml/query.js";
3
+ import { parseXml } from "../xml/parse.js";
4
+ import { decodeEntities } from "../xml/entities.js";
5
+ import { POINTS_PER_PIXEL, detectImageFormat, readImageDimensions } from "../image/dimensions.js";
6
+ import { bytesToBase64 } from "../util/base64.js";
7
+ import { buildXml } from "../xml/build.js";
8
+ import { isFootnoteAside, isFootnoteReferenceAnchor } from "./footnote.js";
9
+ import { HORIZONTAL_RULE_STYLE_ID, MONOSPACE_FONT_FAMILY } from "./style-constants.js";
10
+ import { buildInlineRuns } from "./inline.js";
11
+ import { mintListNumId } from "./list-id.js";
12
+ import { clampHeadingLevel } from "document-schema.js";
13
+ //#region src/xhtml/read.ts
14
+ function createIdMinter() {
15
+ let nextList = 0;
16
+ let nextItem = 0;
17
+ return {
18
+ mintNumId: (options) => {
19
+ nextList += 1;
20
+ return mintListNumId(nextList, options);
21
+ },
22
+ mintItemId: () => {
23
+ nextItem += 1;
24
+ return `item${String(nextItem)}`;
25
+ }
26
+ };
27
+ }
28
+ function withQuote(state) {
29
+ return {
30
+ ...state,
31
+ quoteDepth: state.quoteDepth + 1
32
+ };
33
+ }
34
+ function withListItem(state, listItem) {
35
+ return {
36
+ ...state,
37
+ listItem,
38
+ list: {
39
+ numId: listItem.numId,
40
+ level: listItem.level
41
+ }
42
+ };
43
+ }
44
+ function decorateParagraph(paragraph, state) {
45
+ let decorated = paragraph;
46
+ if (state.quoteDepth > 0) decorated = {
47
+ ...decorated,
48
+ indentLeftPt: state.quoteDepth * 36,
49
+ styleId: decorated.styleId ?? "Quote"
50
+ };
51
+ if (state.listItem !== void 0) {
52
+ const membership = {
53
+ numId: state.listItem.numId,
54
+ level: state.listItem.level,
55
+ itemId: state.listItem.itemId
56
+ };
57
+ decorated = {
58
+ ...decorated,
59
+ list: membership
60
+ };
61
+ }
62
+ return decorated;
63
+ }
64
+ function buildIdElementMap(nodes) {
65
+ const map = /* @__PURE__ */ new Map();
66
+ const stack = [...nodes];
67
+ while (stack.length > 0) {
68
+ const node = stack.pop();
69
+ if (node?.type !== "element") continue;
70
+ const id = attrValue(node, "id");
71
+ if (id !== void 0 && !map.has(id)) map.set(id, node);
72
+ stack.push(...node.children);
73
+ }
74
+ return map;
75
+ }
76
+ function readStyleResidue(html, context) {
77
+ const head = findChildElement(html.children, "head");
78
+ if (head === void 0) return;
79
+ const styleElements = head.children.filter((node) => node.type === "element" && (node.tag === "style" || node.tag === "link" && attrValue(node, "rel") === "stylesheet"));
80
+ if (styleElements.length === 0) return;
81
+ context.sink({
82
+ code: EpubDiagnosticCodes.STYLE_RESIDUE,
83
+ severity: "info",
84
+ message: "the document's own <head> style declarations (CSS) are quarantined as residue rather than interpreted; the schema is content, not styling",
85
+ href: context.sourceHref
86
+ });
87
+ return {
88
+ format: "epub",
89
+ xml: buildXml(styleElements)
90
+ };
91
+ }
92
+ function readXhtmlBody(xml, options) {
93
+ const nodes = parseXml(xml);
94
+ const html = rootElement(nodes);
95
+ const body = html === void 0 ? void 0 : findChildElement(html.children, "body");
96
+ if (body === void 0 || html === void 0) return {
97
+ blocks: [],
98
+ source: void 0
99
+ };
100
+ const idElements = buildIdElementMap(body.children);
101
+ const footnoteTargetIds = /* @__PURE__ */ new Set();
102
+ for (const anchor of elementsWithTag(body.children, "a")) {
103
+ const name = isFootnoteReferenceAnchor(anchor, idElements);
104
+ if (name !== void 0) footnoteTargetIds.add(name);
105
+ }
106
+ const context = {
107
+ resolveImage: options.resolveImage,
108
+ sink: options.sink,
109
+ sourceHref: options.sourceHref,
110
+ idElements,
111
+ footnoteTargetIds,
112
+ quoteDepth: 0
113
+ };
114
+ const state = {
115
+ context,
116
+ minter: createIdMinter(),
117
+ quoteDepth: 0,
118
+ listItem: void 0,
119
+ list: void 0,
120
+ contentWidthPt: options.contentWidthPt
121
+ };
122
+ return {
123
+ blocks: readContainerChildren(body.children, state),
124
+ source: readStyleResidue(html, context)
125
+ };
126
+ }
127
+ const BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
128
+ "p",
129
+ "h1",
130
+ "h2",
131
+ "h3",
132
+ "h4",
133
+ "h5",
134
+ "h6",
135
+ "ul",
136
+ "ol",
137
+ "dl",
138
+ "table",
139
+ "blockquote",
140
+ "pre",
141
+ "hr",
142
+ "figure",
143
+ "figcaption",
144
+ "div",
145
+ "section",
146
+ "article",
147
+ "aside",
148
+ "nav",
149
+ "img"
150
+ ]);
151
+ function readContainerChildren(nodes, state) {
152
+ const blocks = [];
153
+ let segment = [];
154
+ const flush = () => {
155
+ if (segment.length === 0) return;
156
+ const inline = buildInlineRuns(segment, {}, state.context);
157
+ segment = [];
158
+ if (inline.runs.every((run) => run.text.trim().length === 0)) return;
159
+ const paragraph = {
160
+ kind: "paragraph",
161
+ runs: inline.runs,
162
+ ...inline.constructs.length > 0 ? { constructs: inline.constructs } : {}
163
+ };
164
+ blocks.push(decorateParagraph(paragraph, state));
165
+ };
166
+ for (const node of nodes) {
167
+ if (node.type === "element" && BLOCK_LEVEL_TAGS.has(node.tag)) {
168
+ flush();
169
+ blocks.push(...readBlockElement(node, state));
170
+ continue;
171
+ }
172
+ if (node.type === "element" || node.type === "text") segment.push(node);
173
+ }
174
+ flush();
175
+ return blocks;
176
+ }
177
+ function headingLevelOf(tag) {
178
+ const match = /^h([1-6])$/u.exec(tag);
179
+ return match?.[1] === void 0 ? void 0 : clampHeadingLevel(Number(match[1]));
180
+ }
181
+ function readBlockElement(element, state) {
182
+ const id = attrValue(element, "id");
183
+ const isFootnoteTarget = id !== void 0 && state.context.footnoteTargetIds.has(id) && !isFootnoteAside(element);
184
+ const blocks = readBlockElementInner(element, state);
185
+ if (!isFootnoteTarget) return blocks;
186
+ return [
187
+ {
188
+ kind: "constructStart",
189
+ descriptor: {
190
+ kind: "anchor",
191
+ anchorType: "footnote",
192
+ name: id
193
+ }
194
+ },
195
+ ...blocks,
196
+ { kind: "constructEnd" }
197
+ ];
198
+ }
199
+ function readBlockElementInner(element, state) {
200
+ const headingLevel = headingLevelOf(element.tag);
201
+ if (headingLevel !== void 0) {
202
+ const inline = buildInlineRuns(element.children, {}, state.context);
203
+ return [decorateParagraph({
204
+ kind: "paragraph",
205
+ headingLevel,
206
+ runs: inline.runs,
207
+ ...inline.constructs.length > 0 ? { constructs: inline.constructs } : {}
208
+ }, state)];
209
+ }
210
+ switch (element.tag) {
211
+ case "p": return readContainerChildren(element.children, state);
212
+ case "hr": return [decorateParagraph({
213
+ kind: "paragraph",
214
+ runs: [],
215
+ styleId: HORIZONTAL_RULE_STYLE_ID
216
+ }, state)];
217
+ case "pre": return [readPre(element, state)];
218
+ case "blockquote": return readBlockquote(element, state);
219
+ case "ul":
220
+ case "ol": return readList(element, state);
221
+ case "dl": return readDefinitionList(element, state);
222
+ case "table": return [readTable(element, state)];
223
+ case "figure": return readContainerChildren(element.children, state);
224
+ case "figcaption": return [decorateParagraph({
225
+ kind: "paragraph",
226
+ runs: buildInlineRuns(element.children, {}, state.context).runs
227
+ }, state)];
228
+ case "img": {
229
+ const block = readImage(element, state);
230
+ return block === void 0 ? [] : [block];
231
+ }
232
+ case "aside": return readAside(element, state);
233
+ default: return readContainerChildren(element.children, state);
234
+ }
235
+ }
236
+ function readPre(element, state) {
237
+ const languageSource = findChildElement(element.children, "code") ?? element;
238
+ const codeLanguage = languageFromClass(attrValue(languageSource, "class"));
239
+ const text = decodeEntities(textContent(element.children));
240
+ return decorateParagraph({
241
+ kind: "paragraph",
242
+ runs: text.length > 0 ? [{
243
+ text,
244
+ fontFamily: MONOSPACE_FONT_FAMILY
245
+ }] : [],
246
+ ...codeLanguage !== void 0 ? { codeLanguage } : {}
247
+ }, state);
248
+ }
249
+ function languageFromClass(className) {
250
+ if (className === void 0) return;
251
+ return /(?:^|\s)language-(\S+)/u.exec(className)?.[1];
252
+ }
253
+ function containsHeading(nodes) {
254
+ for (const node of nodes) {
255
+ if (node.type !== "element") continue;
256
+ if (headingLevelOf(node.tag) !== void 0) return true;
257
+ if (containsHeading(node.children)) return true;
258
+ }
259
+ return false;
260
+ }
261
+ function readBlockquote(element, state) {
262
+ const nestedState = withQuote(state);
263
+ const blocks = readContainerChildren(element.children, nestedState);
264
+ if (containsHeading(element.children)) return blocks;
265
+ return [
266
+ {
267
+ kind: "constructStart",
268
+ descriptor: { kind: "division" }
269
+ },
270
+ ...blocks,
271
+ { kind: "constructEnd" }
272
+ ];
273
+ }
274
+ function readList(element, state) {
275
+ const numId = state.list?.numId ?? state.minter.mintNumId({
276
+ type: element.tag === "ol" ? "ordered" : "bullet",
277
+ start: startAttr(element)
278
+ });
279
+ const level = state.list === void 0 ? 0 : state.list.level + 1;
280
+ const blocks = [];
281
+ for (const child of element.children) {
282
+ if (child.type !== "element" || child.tag !== "li") continue;
283
+ const itemState = withListItem(state, {
284
+ numId,
285
+ level,
286
+ itemId: state.minter.mintItemId()
287
+ });
288
+ blocks.push(...readContainerChildren(child.children, itemState));
289
+ }
290
+ return blocks;
291
+ }
292
+ function startAttr(element) {
293
+ return positiveIntAttr(element, "start");
294
+ }
295
+ function readDefinitionList(element, state) {
296
+ const blocks = [];
297
+ for (const child of element.children) {
298
+ if (child.type !== "element") continue;
299
+ if (child.tag === "dt") {
300
+ const inline = buildInlineRuns(child.children, {}, state.context);
301
+ blocks.push(decorateParagraph({
302
+ kind: "paragraph",
303
+ runs: inline.runs
304
+ }, state));
305
+ } else if (child.tag === "dd") {
306
+ const inline = buildInlineRuns(child.children, {}, state.context);
307
+ blocks.push(decorateParagraph({
308
+ kind: "paragraph",
309
+ runs: inline.runs,
310
+ indentLeftPt: 36 + state.quoteDepth * 36
311
+ }, state));
312
+ }
313
+ }
314
+ return blocks;
315
+ }
316
+ function readTable(element, state) {
317
+ const rows = [];
318
+ let columnCount = 0;
319
+ for (const section of element.children) {
320
+ if (section.type !== "element") continue;
321
+ const rowContainers = section.tag === "tr" ? [section] : section.tag === "thead" || section.tag === "tbody" || section.tag === "tfoot" ? section.children.filter((c) => c.type === "element" && c.tag === "tr") : [];
322
+ for (const tr of rowContainers) {
323
+ const cells = [];
324
+ for (const cellNode of tr.children) {
325
+ if (cellNode.type !== "element" || cellNode.tag !== "td" && cellNode.tag !== "th") continue;
326
+ const cellStyle = cellNode.tag === "th" ? { bold: true } : {};
327
+ const paragraph = {
328
+ kind: "paragraph",
329
+ runs: buildInlineRuns(cellNode.children, cellStyle, state.context).runs
330
+ };
331
+ const colSpan = positiveIntAttr(cellNode, "colspan");
332
+ const rowSpan = positiveIntAttr(cellNode, "rowspan");
333
+ cells.push({
334
+ blocks: [paragraph],
335
+ ...colSpan !== void 0 ? { colSpan } : {},
336
+ ...rowSpan !== void 0 ? { rowSpan } : {}
337
+ });
338
+ }
339
+ columnCount = Math.max(columnCount, cells.length);
340
+ rows.push({ cells });
341
+ }
342
+ }
343
+ const width = columnCount > 0 ? state.contentWidthPt / columnCount : state.contentWidthPt;
344
+ return {
345
+ kind: "table",
346
+ rows,
347
+ columnWidthsPt: new Array(Math.max(columnCount, 1)).fill(width)
348
+ };
349
+ }
350
+ function positiveIntAttr(element, name) {
351
+ const raw = attrValue(element, name);
352
+ if (raw === void 0) return;
353
+ const value = Number.parseInt(raw, 10);
354
+ return Number.isInteger(value) && value > 0 ? value : void 0;
355
+ }
356
+ function readImage(element, state) {
357
+ const src = attrValue(element, "src");
358
+ const alt = attrValue(element, "alt");
359
+ if (src === void 0) return;
360
+ const bytes = state.context.resolveImage(src);
361
+ if (bytes === void 0) {
362
+ state.context.sink({
363
+ code: EpubDiagnosticCodes.IMAGE_UNRESOLVED,
364
+ severity: "warning",
365
+ message: `<img src="${src}"> names no resolvable manifest part; degraded to its alt text`,
366
+ href: state.context.sourceHref
367
+ });
368
+ return alt === void 0 || alt.length === 0 ? void 0 : decorateParagraph({
369
+ kind: "paragraph",
370
+ runs: [{ text: decodeEntities(alt) }]
371
+ }, state);
372
+ }
373
+ const format = detectImageFormat(bytes);
374
+ const dimensions = readImageDimensions(bytes);
375
+ if (format === void 0 || dimensions === void 0) {
376
+ state.context.sink({
377
+ code: EpubDiagnosticCodes.IMAGE_FORMAT_UNSUPPORTED,
378
+ severity: "warning",
379
+ message: `<img src="${src}"> is neither a PNG nor a JPEG (document-schema.js's ContentImageBlock supports only those two); degraded to its alt text`,
380
+ href: state.context.sourceHref
381
+ });
382
+ return alt === void 0 || alt.length === 0 ? void 0 : decorateParagraph({
383
+ kind: "paragraph",
384
+ runs: [{ text: decodeEntities(alt) }]
385
+ }, state);
386
+ }
387
+ return {
388
+ kind: "image",
389
+ format,
390
+ base64: bytesToBase64(bytes),
391
+ widthPt: dimensions.widthPx * POINTS_PER_PIXEL,
392
+ heightPt: dimensions.heightPx * POINTS_PER_PIXEL,
393
+ ...alt !== void 0 && alt.length > 0 ? { altText: decodeEntities(alt) } : {}
394
+ };
395
+ }
396
+ function readAside(element, state) {
397
+ if (!isFootnoteAside(element)) return readContainerChildren(element.children, state);
398
+ const name = attrValue(element, "id");
399
+ if (name === void 0) {
400
+ state.context.sink({
401
+ code: EpubDiagnosticCodes.FOOTNOTE_TARGET_UNRESOLVED,
402
+ severity: "warning",
403
+ message: "a footnote <aside> carries no id and cannot be referenced; read as ordinary content",
404
+ href: state.context.sourceHref
405
+ });
406
+ return readContainerChildren(element.children, state);
407
+ }
408
+ return [
409
+ {
410
+ kind: "constructStart",
411
+ descriptor: {
412
+ kind: "anchor",
413
+ anchorType: "footnote",
414
+ name
415
+ }
416
+ },
417
+ ...readContainerChildren(element.children, state),
418
+ { kind: "constructEnd" }
419
+ ];
420
+ }
421
+ //#endregion
422
+ export { readXhtmlBody };
@@ -0,0 +1,13 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/xhtml/style-constants.ts
3
+ const HORIZONTAL_RULE_STYLE_ID = "HorizontalRule";
4
+ const QUOTE_STYLE_ID = "Quote";
5
+ const QUOTE_INDENT_PT = 36;
6
+ const MONOSPACE_FONT_FAMILY = "Courier New";
7
+ const DEFINITION_BODY_INDENT_PT = 36;
8
+ //#endregion
9
+ exports.DEFINITION_BODY_INDENT_PT = DEFINITION_BODY_INDENT_PT;
10
+ exports.HORIZONTAL_RULE_STYLE_ID = HORIZONTAL_RULE_STYLE_ID;
11
+ exports.MONOSPACE_FONT_FAMILY = MONOSPACE_FONT_FAMILY;
12
+ exports.QUOTE_INDENT_PT = QUOTE_INDENT_PT;
13
+ exports.QUOTE_STYLE_ID = QUOTE_STYLE_ID;
@@ -0,0 +1,8 @@
1
+ //#region src/xhtml/style-constants.d.ts
2
+ declare const HORIZONTAL_RULE_STYLE_ID = "HorizontalRule";
3
+ declare const QUOTE_STYLE_ID = "Quote";
4
+ declare const QUOTE_INDENT_PT = 36;
5
+ declare const MONOSPACE_FONT_FAMILY = "Courier New";
6
+ declare const DEFINITION_BODY_INDENT_PT = 36;
7
+ //#endregion
8
+ export { DEFINITION_BODY_INDENT_PT, HORIZONTAL_RULE_STYLE_ID, MONOSPACE_FONT_FAMILY, QUOTE_INDENT_PT, QUOTE_STYLE_ID };
@@ -0,0 +1,8 @@
1
+ //#region src/xhtml/style-constants.d.ts
2
+ declare const HORIZONTAL_RULE_STYLE_ID = "HorizontalRule";
3
+ declare const QUOTE_STYLE_ID = "Quote";
4
+ declare const QUOTE_INDENT_PT = 36;
5
+ declare const MONOSPACE_FONT_FAMILY = "Courier New";
6
+ declare const DEFINITION_BODY_INDENT_PT = 36;
7
+ //#endregion
8
+ export { DEFINITION_BODY_INDENT_PT, HORIZONTAL_RULE_STYLE_ID, MONOSPACE_FONT_FAMILY, QUOTE_INDENT_PT, QUOTE_STYLE_ID };
@@ -0,0 +1,8 @@
1
+ //#region src/xhtml/style-constants.ts
2
+ const HORIZONTAL_RULE_STYLE_ID = "HorizontalRule";
3
+ const QUOTE_STYLE_ID = "Quote";
4
+ const QUOTE_INDENT_PT = 36;
5
+ const MONOSPACE_FONT_FAMILY = "Courier New";
6
+ const DEFINITION_BODY_INDENT_PT = 36;
7
+ //#endregion
8
+ export { DEFINITION_BODY_INDENT_PT, HORIZONTAL_RULE_STYLE_ID, MONOSPACE_FONT_FAMILY, QUOTE_INDENT_PT, QUOTE_STYLE_ID };
@@ -0,0 +1,183 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_diagnostics = require("../diagnostics.cjs");
3
+ const require_xml_entities = require("../xml/entities.cjs");
4
+ const require_util_base64 = require("../util/base64.cjs");
5
+ require("./style-constants.cjs");
6
+ const require_xhtml_list_id = require("./list-id.cjs");
7
+ let document_schema_js = require("document-schema.js");
8
+ let document_schema_js_decompose = require("document-schema.js/decompose");
9
+ //#region src/xhtml/write.ts
10
+ function element(tag, attrs = {}, children = []) {
11
+ return {
12
+ type: "element",
13
+ tag,
14
+ attributes: Object.entries(attrs).map(([name, value]) => ({
15
+ name,
16
+ value
17
+ })),
18
+ children
19
+ };
20
+ }
21
+ function text(value) {
22
+ return {
23
+ type: "text",
24
+ value: require_xml_entities.encodeEntities(value)
25
+ };
26
+ }
27
+ function writeXhtmlBody(blocks, context) {
28
+ const { children } = (0, document_schema_js_decompose.decomposeSection)({
29
+ pageSize: {
30
+ widthPt: 1,
31
+ heightPt: 1
32
+ },
33
+ margins: {
34
+ topPt: 0,
35
+ rightPt: 0,
36
+ bottomPt: 0,
37
+ leftPt: 0
38
+ },
39
+ blocks: [...blocks]
40
+ });
41
+ return element("body", {}, writeSectionChildren(children, context));
42
+ }
43
+ function writeSectionChildren(children, context) {
44
+ const out = [];
45
+ let index = 0;
46
+ while (index < children.length) {
47
+ const child = children[index];
48
+ if (child === void 0) break;
49
+ if ((0, document_schema_js.isListGroupNode)(child)) {
50
+ let end = index;
51
+ while (end < children.length && (0, document_schema_js.isListGroupNode)(children[end])) end += 1;
52
+ const items = children.slice(index, end);
53
+ out.push(writeList(items, context));
54
+ index = end;
55
+ continue;
56
+ }
57
+ out.push(...writeSectionChild(child, context));
58
+ index += 1;
59
+ }
60
+ return out;
61
+ }
62
+ function writeSectionChild(child, context) {
63
+ if ((0, document_schema_js.isHeadingGroupNode)(child)) return [writeHeading(child), ...writeSectionChildren(child.children, context)];
64
+ if ((0, document_schema_js.isListGroupNode)(child)) return [writeList([child], context)];
65
+ if ((0, document_schema_js.isSectionConstructGroupNode)(child)) return writeSectionConstructGroup(child, context);
66
+ return writeLeafBlock(child, context);
67
+ }
68
+ function writeHeading(group) {
69
+ const level = Math.min(6, Math.max(1, group.node.headingLevel));
70
+ return element(`h${String(level)}`, {}, writeRunsToNodes(group.node.runs, group.node.constructs));
71
+ }
72
+ function writeList(items, context) {
73
+ const numId = items[0]?.node.list.numId;
74
+ const info = numId === void 0 ? void 0 : require_xhtml_list_id.parseListNumId(numId);
75
+ return element(info?.type === "ordered" ? "ol" : "ul", info?.type === "ordered" && info.start !== void 0 ? { start: String(info.start) } : {}, items.map((item) => {
76
+ const paragraph = item.node;
77
+ const anchorNodes = writeRunsToNodes(paragraph.runs, paragraph.constructs);
78
+ const nested = writeSectionChildren(item.children, context);
79
+ return element("li", {}, [...anchorNodes, ...nested]);
80
+ }));
81
+ }
82
+ function writeSectionConstructGroup(group, context) {
83
+ const descriptor = group.node;
84
+ if (descriptor.kind === "division") return [element("blockquote", {}, writeSectionChildren(group.children, context))];
85
+ if (descriptor.kind === "anchor" && descriptor.anchorType === "footnote") return [element("aside", {
86
+ "epub:type": "footnote",
87
+ id: descriptor.name
88
+ }, writeSectionChildren(group.children, context))];
89
+ context.sink({
90
+ code: require_diagnostics.EpubDiagnosticCodes.CONSTRUCT_UNREPRESENTED,
91
+ severity: "info",
92
+ message: `a '${descriptor.kind}' construct has no XHTML spelling in this package's writer; its extent is written, the construct itself is not`,
93
+ href: context.sourceHref
94
+ });
95
+ return writeSectionChildren(group.children, context);
96
+ }
97
+ function writeLeafBlock(block, context) {
98
+ switch (block.kind) {
99
+ case "paragraph": return [writeParagraph(block)];
100
+ case "table": return [writeTable(block, context)];
101
+ case "image": return [writeImage(block, context)];
102
+ case "pageBreak": return [];
103
+ case "embeddedObject":
104
+ context.sink({
105
+ code: require_diagnostics.EpubDiagnosticCodes.ELEMENT_UNMAPPED,
106
+ severity: "warning",
107
+ message: "an embedded object has no XHTML representation in this package's writer and was dropped",
108
+ href: context.sourceHref
109
+ });
110
+ return [];
111
+ }
112
+ }
113
+ function isPreBlockParagraph(paragraph) {
114
+ if (paragraph.codeLanguage !== void 0) return true;
115
+ return paragraph.runs.length === 1 && paragraph.runs[0]?.fontFamily === "Courier New" && paragraph.runs[0].text.includes("\n");
116
+ }
117
+ function writeParagraph(paragraph) {
118
+ if (paragraph.styleId === "HorizontalRule" && paragraph.runs.length === 0) return element("hr");
119
+ if (isPreBlockParagraph(paragraph)) return element("pre", {}, [element("code", paragraph.codeLanguage === void 0 ? {} : { class: `language-${paragraph.codeLanguage}` }, [text(paragraph.runs.map((run) => run.text).join(""))])]);
120
+ return element("p", {}, writeRunsToNodes(paragraph.runs, paragraph.constructs));
121
+ }
122
+ function isFootnoteExtent(construct) {
123
+ return construct.descriptor.kind === "anchor" && construct.descriptor.anchorType === "footnote";
124
+ }
125
+ function writeRunsToNodes(runs, constructs) {
126
+ const footnoteExtents = (constructs ?? []).filter(isFootnoteExtent);
127
+ const out = [];
128
+ let index = 0;
129
+ while (index < runs.length) {
130
+ const extent = footnoteExtents.find((e) => e.startRun === index);
131
+ if (extent !== void 0) {
132
+ const inner = runs.slice(extent.startRun, extent.endRun).flatMap((run) => writeRunNodes(run));
133
+ out.push(element("a", {
134
+ "epub:type": "noteref",
135
+ href: `#${extent.descriptor.name}`
136
+ }, inner));
137
+ index = Math.max(extent.endRun, index + 1);
138
+ continue;
139
+ }
140
+ const run = runs[index];
141
+ if (run !== void 0) out.push(...writeRunNodes(run));
142
+ index += 1;
143
+ }
144
+ return out;
145
+ }
146
+ function writeRunNodes(run) {
147
+ const segments = run.text.split("\n");
148
+ let nodes = [];
149
+ segments.forEach((segment, i) => {
150
+ if (i > 0) nodes.push(element("br"));
151
+ if (segment.length > 0) nodes.push(text(segment));
152
+ });
153
+ if (nodes.length === 0) nodes = [text("")];
154
+ if (run.fontFamily === "Courier New") nodes = [element("code", {}, nodes)];
155
+ if (run.bold === true) nodes = [element("strong", {}, nodes)];
156
+ if (run.italic === true) nodes = [element("em", {}, nodes)];
157
+ if (run.underline === true) nodes = [element("u", {}, nodes)];
158
+ if (run.strike === true) nodes = [element("s", {}, nodes)];
159
+ if (run.hyperlink !== void 0) nodes = [element("a", { href: run.hyperlink }, nodes)];
160
+ return nodes;
161
+ }
162
+ function writeTable(table, context) {
163
+ return element("table", {}, table.rows.map((row) => element("tr", {}, row.cells.map((cell) => {
164
+ const attrs = {};
165
+ if (cell.colSpan !== void 0) attrs.colspan = String(cell.colSpan);
166
+ if (cell.rowSpan !== void 0) attrs.rowspan = String(cell.rowSpan);
167
+ for (const block of cell.blocks) if (!(0, document_schema_js.isTreeBlockLeaf)(block)) context.sink({
168
+ code: require_diagnostics.EpubDiagnosticCodes.ELEMENT_UNMAPPED,
169
+ severity: "info",
170
+ message: "a construct-boundary marker inside a table cell has no XHTML representation in this package's writer and was dropped",
171
+ href: context.sourceHref
172
+ });
173
+ return element("td", attrs, cell.blocks.filter(document_schema_js.isTreeBlockLeaf).flatMap((block) => writeLeafBlock(block, context)));
174
+ }))));
175
+ }
176
+ function writeImage(image, context) {
177
+ const bytes = require_util_base64.base64ToBytes(image.base64);
178
+ const attrs = { src: context.registerImage(bytes, image.format) };
179
+ attrs.alt = image.altText ?? "";
180
+ return element("img", attrs);
181
+ }
182
+ //#endregion
183
+ exports.writeXhtmlBody = writeXhtmlBody;
@@ -0,0 +1,12 @@
1
+ import { i as EpubDiagnosticSink } from "../diagnostics-Ee4kG7mw.cjs";
2
+ import { XmlElement } from "../xml/node.cjs";
3
+ import { ContentBlock } from "document-schema.js";
4
+ //#region src/xhtml/write.d.ts
5
+ interface XhtmlWriteContext {
6
+ readonly registerImage: (bytes: Uint8Array<ArrayBuffer>, format: "png" | "jpeg") => string;
7
+ readonly sink: EpubDiagnosticSink;
8
+ readonly sourceHref: string;
9
+ }
10
+ declare function writeXhtmlBody(blocks: readonly ContentBlock[], context: XhtmlWriteContext): XmlElement;
11
+ //#endregion
12
+ export { XhtmlWriteContext, writeXhtmlBody };
@@ -0,0 +1,12 @@
1
+ import { i as EpubDiagnosticSink } from "../diagnostics-Ee4kG7mw.js";
2
+ import { XmlElement } from "../xml/node.js";
3
+ import { ContentBlock } from "document-schema.js";
4
+ //#region src/xhtml/write.d.ts
5
+ interface XhtmlWriteContext {
6
+ readonly registerImage: (bytes: Uint8Array<ArrayBuffer>, format: "png" | "jpeg") => string;
7
+ readonly sink: EpubDiagnosticSink;
8
+ readonly sourceHref: string;
9
+ }
10
+ declare function writeXhtmlBody(blocks: readonly ContentBlock[], context: XhtmlWriteContext): XmlElement;
11
+ //#endregion
12
+ export { XhtmlWriteContext, writeXhtmlBody };