mark-epub-down 0.1.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/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/application/convert-epub-document.d.ts +10 -0
- package/dist/application/convert-epub-document.js +80 -0
- package/dist/application/convert-epub-document.js.map +1 -0
- package/dist/application/convert-epub.d.ts +13 -0
- package/dist/application/convert-epub.js +35 -0
- package/dist/application/convert-epub.js.map +1 -0
- package/dist/cli/confirm-overwrite.d.ts +1 -0
- package/dist/cli/confirm-overwrite.js +29 -0
- package/dist/cli/confirm-overwrite.js.map +1 -0
- package/dist/cli/reporting.d.ts +3 -0
- package/dist/cli/reporting.js +24 -0
- package/dist/cli/reporting.js.map +1 -0
- package/dist/cli/run-convert-command.d.ts +10 -0
- package/dist/cli/run-convert-command.js +61 -0
- package/dist/cli/run-convert-command.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +28 -0
- package/dist/cli.js.map +1 -0
- package/dist/domain/errors.d.ts +7 -0
- package/dist/domain/errors.js +20 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/spec.d.ts +8 -0
- package/dist/domain/spec.js +49 -0
- package/dist/domain/spec.js.map +1 -0
- package/dist/domain/types.d.ts +48 -0
- package/dist/domain/types.js +3 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/warnings.d.ts +8 -0
- package/dist/domain/warnings.js +49 -0
- package/dist/domain/warnings.js.map +1 -0
- package/dist/epub/archive.d.ts +3 -0
- package/dist/epub/archive.js +22 -0
- package/dist/epub/archive.js.map +1 -0
- package/dist/epub/container.d.ts +2 -0
- package/dist/epub/container.js +46 -0
- package/dist/epub/container.js.map +1 -0
- package/dist/epub/content.d.ts +7 -0
- package/dist/epub/content.js +34 -0
- package/dist/epub/content.js.map +1 -0
- package/dist/epub/opf.d.ts +2 -0
- package/dist/epub/opf.js +122 -0
- package/dist/epub/opf.js.map +1 -0
- package/dist/epub/spine.d.ts +2 -0
- package/dist/epub/spine.js +25 -0
- package/dist/epub/spine.js.map +1 -0
- package/dist/epub/toc.d.ts +3 -0
- package/dist/epub/toc.js +165 -0
- package/dist/epub/toc.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/output/render.d.ts +9 -0
- package/dist/output/render.js +54 -0
- package/dist/output/render.js.map +1 -0
- package/dist/transform/anchors.d.ts +2 -0
- package/dist/transform/anchors.js +18 -0
- package/dist/transform/anchors.js.map +1 -0
- package/dist/transform/cleanup.d.ts +4 -0
- package/dist/transform/cleanup.js +37 -0
- package/dist/transform/cleanup.js.map +1 -0
- package/dist/transform/links.d.ts +14 -0
- package/dist/transform/links.js +174 -0
- package/dist/transform/links.js.map +1 -0
- package/dist/transform/markdown.d.ts +2 -0
- package/dist/transform/markdown.js +102 -0
- package/dist/transform/markdown.js.map +1 -0
- package/dist/transform/tables.d.ts +5 -0
- package/dist/transform/tables.js +130 -0
- package/dist/transform/tables.js.map +1 -0
- package/dist/utils/epub-path.d.ts +14 -0
- package/dist/utils/epub-path.js +56 -0
- package/dist/utils/epub-path.js.map +1 -0
- package/dist/utils/path.d.ts +2 -0
- package/dist/utils/path.js +33 -0
- package/dist/utils/path.js.map +1 -0
- package/docs/epub-to-md-v1-public-spec.md +176 -0
- package/docs/v1-technical-selection.md +106 -0
- package/package.json +67 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FRONT_MATTER_FIELDS } from "./spec";
|
|
2
|
+
export type MetadataField = (typeof FRONT_MATTER_FIELDS)[number];
|
|
3
|
+
export type BookMetadata = Partial<Record<MetadataField, string>>;
|
|
4
|
+
export interface WarningRecord {
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ContainerDocument {
|
|
9
|
+
opfPath: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ManifestItem {
|
|
12
|
+
id: string;
|
|
13
|
+
href: string;
|
|
14
|
+
mediaType: string;
|
|
15
|
+
properties: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface SpineItemRef {
|
|
18
|
+
idref: string;
|
|
19
|
+
linear: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ParsedPackageDocument {
|
|
22
|
+
opfPath: string;
|
|
23
|
+
opfDirectory: string;
|
|
24
|
+
metadata: BookMetadata;
|
|
25
|
+
manifestItems: ManifestItem[];
|
|
26
|
+
manifestById: Map<string, ManifestItem>;
|
|
27
|
+
spine: SpineItemRef[];
|
|
28
|
+
navigation: {
|
|
29
|
+
navItemId?: string;
|
|
30
|
+
ncxItemId?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface TocItem {
|
|
34
|
+
label: string;
|
|
35
|
+
href?: string;
|
|
36
|
+
children: TocItem[];
|
|
37
|
+
}
|
|
38
|
+
export interface TocDocument {
|
|
39
|
+
source: "nav" | "ncx" | "missing";
|
|
40
|
+
items: TocItem[];
|
|
41
|
+
}
|
|
42
|
+
export interface SpineDocument {
|
|
43
|
+
idref: string;
|
|
44
|
+
linear: boolean;
|
|
45
|
+
manifestItem: ManifestItem;
|
|
46
|
+
absolutePath: string;
|
|
47
|
+
relativePath: string;
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/domain/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WarningRecord } from "./types";
|
|
2
|
+
export declare class WarningCollector {
|
|
3
|
+
private readonly warnings;
|
|
4
|
+
add(code: string, message: string): void;
|
|
5
|
+
list(): WarningRecord[];
|
|
6
|
+
}
|
|
7
|
+
export declare function getCliVisibleWarnings(warnings: WarningRecord[]): WarningRecord[];
|
|
8
|
+
export declare function summarizeWarnings(warnings: WarningRecord[]): WarningRecord[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WarningCollector = void 0;
|
|
4
|
+
exports.getCliVisibleWarnings = getCliVisibleWarnings;
|
|
5
|
+
exports.summarizeWarnings = summarizeWarnings;
|
|
6
|
+
const WARNING_VISIBILITY = {
|
|
7
|
+
ELEMENTS_DROPPED: "structured-only",
|
|
8
|
+
};
|
|
9
|
+
class WarningCollector {
|
|
10
|
+
warnings = [];
|
|
11
|
+
add(code, message) {
|
|
12
|
+
this.warnings.push({ code, message });
|
|
13
|
+
}
|
|
14
|
+
list() {
|
|
15
|
+
return [...this.warnings];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.WarningCollector = WarningCollector;
|
|
19
|
+
function getCliVisibleWarnings(warnings) {
|
|
20
|
+
return warnings.filter((warning) => getWarningVisibility(warning.code) === "cli");
|
|
21
|
+
}
|
|
22
|
+
function summarizeWarnings(warnings) {
|
|
23
|
+
const counts = new Map();
|
|
24
|
+
for (const warning of warnings) {
|
|
25
|
+
const key = `${warning.code}\u0000${warning.message}`;
|
|
26
|
+
const existing = counts.get(key);
|
|
27
|
+
if (existing) {
|
|
28
|
+
existing.count += 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
counts.set(key, {
|
|
32
|
+
warning,
|
|
33
|
+
count: 1,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return [...counts.values()].map(({ warning, count }) => {
|
|
37
|
+
if (count === 1) {
|
|
38
|
+
return warning;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
code: warning.code,
|
|
42
|
+
message: `${warning.message} (${count} occurrences)`,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function getWarningVisibility(code) {
|
|
47
|
+
return WARNING_VISIBILITY[code] ?? "cli";
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=warnings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warnings.js","sourceRoot":"","sources":["../../src/domain/warnings.ts"],"names":[],"mappings":";;;AAoBA,sDAEC;AAED,8CA4BC;AAhDD,MAAM,kBAAkB,GAAsC;IAC5D,gBAAgB,EAAE,iBAAiB;CACpC,CAAC;AAEF,MAAa,gBAAgB;IACV,QAAQ,GAAoB,EAAE,CAAC;IAEzC,GAAG,CAAC,IAAY,EAAE,OAAe;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACxC,CAAC;IAEM,IAAI;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;CACF;AAVD,4CAUC;AAED,SAAgB,qBAAqB,CAAC,QAAyB;IAC7D,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;AACpF,CAAC;AAED,SAAgB,iBAAiB,CAAC,QAAyB;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqD,CAAC;IAE5E,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,IAAI,SAAS,OAAO,CAAC,OAAO,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEjC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE;YACd,OAAO;YACP,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QACrD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,OAAO;YACL,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,KAAK,KAAK,eAAe;SACrD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAY;IACxC,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createWorkingDirectory = createWorkingDirectory;
|
|
7
|
+
exports.extractArchive = extractArchive;
|
|
8
|
+
exports.cleanupWorkingDirectory = cleanupWorkingDirectory;
|
|
9
|
+
const promises_1 = require("node:fs/promises");
|
|
10
|
+
const node_os_1 = require("node:os");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const extract_zip_1 = __importDefault(require("extract-zip"));
|
|
13
|
+
async function createWorkingDirectory() {
|
|
14
|
+
return (0, promises_1.mkdtemp)(node_path_1.default.join((0, node_os_1.tmpdir)(), "epub2md-"));
|
|
15
|
+
}
|
|
16
|
+
async function extractArchive(inputPath, workingDirectory) {
|
|
17
|
+
await (0, extract_zip_1.default)(inputPath, { dir: workingDirectory });
|
|
18
|
+
}
|
|
19
|
+
async function cleanupWorkingDirectory(workingDirectory) {
|
|
20
|
+
await (0, promises_1.rm)(workingDirectory, { recursive: true, force: true });
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/epub/archive.ts"],"names":[],"mappings":";;;;;AAMA,wDAEC;AAED,wCAEC;AAED,0DAEC;AAhBD,+CAA+C;AAC/C,qCAAiC;AACjC,0DAA6B;AAE7B,8DAAkC;AAE3B,KAAK,UAAU,sBAAsB;IAC1C,OAAO,IAAA,kBAAO,EAAC,mBAAI,CAAC,IAAI,CAAC,IAAA,gBAAM,GAAE,EAAE,UAAU,CAAC,CAAC,CAAC;AAClD,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,SAAiB,EAAE,gBAAwB;IAC9E,MAAM,IAAA,qBAAO,EAAC,SAAS,EAAE,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;AACtD,CAAC;AAEM,KAAK,UAAU,uBAAuB,CAAC,gBAAwB;IACpE,MAAM,IAAA,aAAE,EAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseContainerDocument = parseContainerDocument;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
10
|
+
const errors_1 = require("../domain/errors");
|
|
11
|
+
const parser = new fast_xml_parser_1.XMLParser({
|
|
12
|
+
ignoreAttributes: false,
|
|
13
|
+
attributeNamePrefix: "",
|
|
14
|
+
removeNSPrefix: true,
|
|
15
|
+
trimValues: true,
|
|
16
|
+
});
|
|
17
|
+
async function parseContainerDocument(workingDirectory) {
|
|
18
|
+
const containerPath = node_path_1.default.join(workingDirectory, "META-INF", "container.xml");
|
|
19
|
+
let containerXml;
|
|
20
|
+
try {
|
|
21
|
+
containerXml = await (0, promises_1.readFile)(containerPath, "utf8");
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw errors_1.ConversionError.fatal("CONTAINER_XML_MISSING", "EPUB container.xml is missing or unreadable.");
|
|
25
|
+
}
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = parser.parse(containerXml);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw errors_1.ConversionError.fatal("CONTAINER_XML_INVALID", "EPUB container.xml could not be parsed.");
|
|
32
|
+
}
|
|
33
|
+
const rootfiles = asArray(parsed.container?.rootfiles?.rootfile);
|
|
34
|
+
const opfPath = rootfiles.find((rootfile) => typeof rootfile?.["full-path"] === "string")?.["full-path"];
|
|
35
|
+
if (!opfPath) {
|
|
36
|
+
throw errors_1.ConversionError.fatal("OPF_NOT_FOUND", "EPUB container.xml did not provide a package document path.");
|
|
37
|
+
}
|
|
38
|
+
return { opfPath };
|
|
39
|
+
}
|
|
40
|
+
function asArray(value) {
|
|
41
|
+
if (!value) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
return Array.isArray(value) ? value : [value];
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/epub/container.ts"],"names":[],"mappings":";;;;;AAeA,wDA6CC;AA5DD,+CAA4C;AAC5C,0DAA6B;AAE7B,qDAA4C;AAE5C,6CAAmD;AAGnD,MAAM,MAAM,GAAG,IAAI,2BAAS,CAAC;IAC3B,gBAAgB,EAAE,KAAK;IACvB,mBAAmB,EAAE,EAAE;IACvB,cAAc,EAAE,IAAI;IACpB,UAAU,EAAE,IAAI;CACjB,CAAC,CAAC;AAEI,KAAK,UAAU,sBAAsB,CAAC,gBAAwB;IACnE,MAAM,aAAa,GAAG,mBAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IAE/E,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,IAAA,mBAAQ,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,wBAAe,CAAC,KAAK,CACzB,uBAAuB,EACvB,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,wBAAe,CAAC,KAAK,CACzB,uBAAuB,EACvB,yCAAyC,CAC1C,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CACtB,MAMC,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAClC,CAAC;IAEF,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,QAAQ,EAAE,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,EAAE,CACzF,WAAW,CACZ,CAAC;IAEF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,wBAAe,CAAC,KAAK,CACzB,eAAe,EACf,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,OAAO,CAAI,KAA0B;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { JSDOM } from "jsdom";
|
|
2
|
+
import type { SpineDocument } from "../domain/types";
|
|
3
|
+
export interface LoadedSpineDocument {
|
|
4
|
+
spineDocument: SpineDocument;
|
|
5
|
+
dom: JSDOM;
|
|
6
|
+
}
|
|
7
|
+
export declare function loadSpineDocuments(workingDirectory: string, spineDocuments: SpineDocument[]): Promise<LoadedSpineDocument[]>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadSpineDocuments = loadSpineDocuments;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const jsdom_1 = require("jsdom");
|
|
10
|
+
const errors_1 = require("../domain/errors");
|
|
11
|
+
async function loadSpineDocuments(workingDirectory, spineDocuments) {
|
|
12
|
+
return Promise.all(spineDocuments.map(async (spineDocument) => {
|
|
13
|
+
const absolutePath = node_path_1.default.join(workingDirectory, spineDocument.relativePath);
|
|
14
|
+
let source;
|
|
15
|
+
try {
|
|
16
|
+
source = await (0, promises_1.readFile)(absolutePath, "utf8");
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
throw errors_1.ConversionError.fatal("CONTENT_UNREADABLE", `spine content resource could not be read: ${spineDocument.relativePath}`);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return {
|
|
23
|
+
spineDocument,
|
|
24
|
+
dom: new jsdom_1.JSDOM(source, {
|
|
25
|
+
contentType: "application/xhtml+xml",
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw errors_1.ConversionError.fatal("CONTENT_INVALID", `spine content resource could not be parsed as XHTML: ${spineDocument.relativePath}`);
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/epub/content.ts"],"names":[],"mappings":";;;;;AAaA,gDAiCC;AA9CD,+CAA4C;AAC5C,0DAA6B;AAE7B,iCAA8B;AAE9B,6CAAmD;AAQ5C,KAAK,UAAU,kBAAkB,CACtC,gBAAwB,EACxB,cAA+B;IAE/B,OAAO,OAAO,CAAC,GAAG,CAChB,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;QACzC,MAAM,YAAY,GAAG,mBAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QAE7E,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,IAAA,mBAAQ,EAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,wBAAe,CAAC,KAAK,CACzB,oBAAoB,EACpB,6CAA6C,aAAa,CAAC,YAAY,EAAE,CAC1E,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,OAAO;gBACL,aAAa;gBACb,GAAG,EAAE,IAAI,aAAK,CAAC,MAAM,EAAE;oBACrB,WAAW,EAAE,uBAAuB;iBACrC,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,wBAAe,CAAC,KAAK,CACzB,iBAAiB,EACjB,wDAAwD,aAAa,CAAC,YAAY,EAAE,CACrF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
package/dist/epub/opf.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parsePackageDocument = parsePackageDocument;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
10
|
+
const errors_1 = require("../domain/errors");
|
|
11
|
+
const parser = new fast_xml_parser_1.XMLParser({
|
|
12
|
+
ignoreAttributes: false,
|
|
13
|
+
attributeNamePrefix: "",
|
|
14
|
+
removeNSPrefix: true,
|
|
15
|
+
trimValues: true,
|
|
16
|
+
});
|
|
17
|
+
async function parsePackageDocument(workingDirectory, opfRelativePath) {
|
|
18
|
+
const opfPath = node_path_1.default.join(workingDirectory, opfRelativePath);
|
|
19
|
+
let opfXml;
|
|
20
|
+
try {
|
|
21
|
+
opfXml = await (0, promises_1.readFile)(opfPath, "utf8");
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw errors_1.ConversionError.fatal("OPF_UNREADABLE", `package document could not be read: ${opfRelativePath}`);
|
|
25
|
+
}
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = parser.parse(opfXml);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw errors_1.ConversionError.fatal("OPF_INVALID", `package document could not be parsed: ${opfRelativePath}`);
|
|
32
|
+
}
|
|
33
|
+
const packageNode = parsed.package;
|
|
34
|
+
if (!packageNode?.manifest || !packageNode.spine) {
|
|
35
|
+
throw errors_1.ConversionError.fatal("OPF_MISSING_CORE_SECTIONS", "package document is missing manifest or spine.");
|
|
36
|
+
}
|
|
37
|
+
const manifestItems = asArray(packageNode.manifest.item).map(mapManifestItem);
|
|
38
|
+
const manifestById = new Map(manifestItems.map((item) => [item.id, item]));
|
|
39
|
+
const spine = asArray(packageNode.spine.itemref).map(mapSpineItem);
|
|
40
|
+
if (spine.length === 0) {
|
|
41
|
+
throw errors_1.ConversionError.fatal("SPINE_EMPTY", "package document spine is empty.");
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
opfPath: opfRelativePath,
|
|
45
|
+
opfDirectory: node_path_1.default.dirname(opfRelativePath),
|
|
46
|
+
metadata: mapMetadata(packageNode.metadata ?? {}),
|
|
47
|
+
manifestItems,
|
|
48
|
+
manifestById,
|
|
49
|
+
spine,
|
|
50
|
+
navigation: {
|
|
51
|
+
navItemId: manifestItems.find((item) => item.properties.includes("nav"))?.id,
|
|
52
|
+
ncxItemId: packageNode.spine.toc,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function mapMetadata(metadataNode) {
|
|
57
|
+
return {
|
|
58
|
+
title: readFirstString(metadataNode.title),
|
|
59
|
+
creator: readFirstString(metadataNode.creator),
|
|
60
|
+
language: readFirstString(metadataNode.language),
|
|
61
|
+
identifier: readFirstString(metadataNode.identifier),
|
|
62
|
+
publisher: readFirstString(metadataNode.publisher),
|
|
63
|
+
published: normalizePublishedDate(readFirstString(metadataNode.date)),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function normalizePublishedDate(value) {
|
|
67
|
+
if (!value) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const trimmed = value.trim();
|
|
71
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
72
|
+
return trimmed;
|
|
73
|
+
}
|
|
74
|
+
if (/^\d{4}-\d{2}-\d{2}(?:[Tt ].+)$/.test(trimmed)) {
|
|
75
|
+
return trimmed.slice(0, 10);
|
|
76
|
+
}
|
|
77
|
+
return trimmed;
|
|
78
|
+
}
|
|
79
|
+
function mapManifestItem(node) {
|
|
80
|
+
const id = node.id;
|
|
81
|
+
const href = node.href;
|
|
82
|
+
const mediaType = node["media-type"];
|
|
83
|
+
if (!id || !href || !mediaType) {
|
|
84
|
+
throw errors_1.ConversionError.fatal("MANIFEST_ITEM_INVALID", "manifest item is missing id, href, or media-type.");
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
id,
|
|
88
|
+
href,
|
|
89
|
+
mediaType,
|
|
90
|
+
properties: node.properties ? node.properties.split(/\s+/).filter(Boolean) : [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function mapSpineItem(node) {
|
|
94
|
+
if (!node.idref) {
|
|
95
|
+
throw errors_1.ConversionError.fatal("SPINE_ITEM_INVALID", "spine item is missing idref.");
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
idref: node.idref,
|
|
99
|
+
linear: node.linear !== "no",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function readFirstString(value) {
|
|
103
|
+
if (typeof value === "string" && value.length > 0) {
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
const first = value.find((entry) => typeof entry === "string" && entry.length > 0);
|
|
108
|
+
return typeof first === "string" ? first : undefined;
|
|
109
|
+
}
|
|
110
|
+
if (value && typeof value === "object" && "#text" in value) {
|
|
111
|
+
const text = value["#text"];
|
|
112
|
+
return typeof text === "string" && text.length > 0 ? text : undefined;
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
function asArray(value) {
|
|
117
|
+
if (!value) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
return Array.isArray(value) ? value : [value];
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=opf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opf.js","sourceRoot":"","sources":["../../src/epub/opf.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildSpineIndex = buildSpineIndex;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const errors_1 = require("../domain/errors");
|
|
9
|
+
const epub_path_1 = require("../utils/epub-path");
|
|
10
|
+
function buildSpineIndex(packageDocument) {
|
|
11
|
+
return packageDocument.spine.map((spineItem) => {
|
|
12
|
+
const manifestItem = packageDocument.manifestById.get(spineItem.idref);
|
|
13
|
+
if (!manifestItem) {
|
|
14
|
+
throw errors_1.ConversionError.fatal("SPINE_TARGET_MISSING", `spine item ${spineItem.idref} does not resolve to a manifest item.`);
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
idref: spineItem.idref,
|
|
18
|
+
linear: spineItem.linear,
|
|
19
|
+
manifestItem,
|
|
20
|
+
relativePath: (0, epub_path_1.normalizeEpubPath)(node_path_1.default.posix.join(packageDocument.opfDirectory, manifestItem.href)),
|
|
21
|
+
absolutePath: (0, epub_path_1.normalizeEpubPath)(node_path_1.default.posix.join(node_path_1.default.posix.dirname(packageDocument.opfPath), manifestItem.href)),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=spine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine.js","sourceRoot":"","sources":["../../src/epub/spine.ts"],"names":[],"mappings":";;;;;AAMA,0CAmBC;AAzBD,0DAA6B;AAE7B,6CAAmD;AAEnD,kDAAuD;AAEvD,SAAgB,eAAe,CAAC,eAAsC;IACpE,OAAO,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;QAC7C,MAAM,YAAY,GAAG,eAAe,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAEvE,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,wBAAe,CAAC,KAAK,CACzB,sBAAsB,EACtB,cAAc,SAAS,CAAC,KAAK,uCAAuC,CACrE,CAAC;QACJ,CAAC;QAED,OAAO;YACL,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,YAAY;YACZ,YAAY,EAAE,IAAA,6BAAiB,EAAC,mBAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;YACjG,YAAY,EAAE,IAAA,6BAAiB,EAAC,mBAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;SACjH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ParsedPackageDocument, TocDocument } from "../domain/types";
|
|
2
|
+
import { WarningCollector } from "../domain/warnings";
|
|
3
|
+
export declare function parseTocDocument(workingDirectory: string, packageDocument: ParsedPackageDocument, warnings: WarningCollector): Promise<TocDocument>;
|
package/dist/epub/toc.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseTocDocument = parseTocDocument;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
10
|
+
const jsdom_1 = require("jsdom");
|
|
11
|
+
const epub_path_1 = require("../utils/epub-path");
|
|
12
|
+
const xmlParser = new fast_xml_parser_1.XMLParser({
|
|
13
|
+
ignoreAttributes: false,
|
|
14
|
+
attributeNamePrefix: "",
|
|
15
|
+
removeNSPrefix: true,
|
|
16
|
+
trimValues: true,
|
|
17
|
+
});
|
|
18
|
+
async function parseTocDocument(workingDirectory, packageDocument, warnings) {
|
|
19
|
+
const navItemId = packageDocument.navigation.navItemId;
|
|
20
|
+
if (navItemId) {
|
|
21
|
+
const navItem = packageDocument.manifestById.get(navItemId);
|
|
22
|
+
if (navItem) {
|
|
23
|
+
const navDocumentPath = node_path_1.default.posix.join(packageDocument.opfDirectory, navItem.href);
|
|
24
|
+
const navPath = node_path_1.default.join(workingDirectory, packageDocument.opfDirectory, navItem.href);
|
|
25
|
+
const navDocument = await parseNavDocument(navPath, navDocumentPath, warnings);
|
|
26
|
+
if (navDocument) {
|
|
27
|
+
return navDocument;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const ncxItemId = packageDocument.navigation.ncxItemId;
|
|
32
|
+
if (ncxItemId) {
|
|
33
|
+
const ncxItem = packageDocument.manifestById.get(ncxItemId);
|
|
34
|
+
if (ncxItem) {
|
|
35
|
+
const ncxDocumentPath = node_path_1.default.posix.join(packageDocument.opfDirectory, ncxItem.href);
|
|
36
|
+
const ncxPath = node_path_1.default.join(workingDirectory, packageDocument.opfDirectory, ncxItem.href);
|
|
37
|
+
const ncxDocument = await parseNcxDocument(ncxPath, ncxDocumentPath, warnings);
|
|
38
|
+
if (ncxDocument) {
|
|
39
|
+
return ncxDocument;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
warnings.add("TOC_MISSING", "table of contents metadata could not be read; the generated TOC section will be empty.");
|
|
44
|
+
return {
|
|
45
|
+
source: "missing",
|
|
46
|
+
items: [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function parseNavDocument(navPath, navDocumentPath, warnings) {
|
|
50
|
+
let navContent;
|
|
51
|
+
try {
|
|
52
|
+
navContent = await (0, promises_1.readFile)(navPath, "utf8");
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
warnings.add("TOC_NAV_UNREADABLE", `nav TOC document could not be read; trying other TOC sources: ${navDocumentPath}`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
let dom;
|
|
59
|
+
try {
|
|
60
|
+
dom = new jsdom_1.JSDOM(navContent, {
|
|
61
|
+
contentType: "application/xhtml+xml",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
warnings.add("TOC_NAV_INVALID", `nav TOC document could not be parsed; trying other TOC sources: ${navDocumentPath}`);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const navNodes = Array.from(dom.window.document.querySelectorAll("nav"));
|
|
69
|
+
const tocNode = navNodes.find((node) => {
|
|
70
|
+
const type = node.getAttribute("epub:type") ?? node.getAttribute("type");
|
|
71
|
+
return type === "toc";
|
|
72
|
+
});
|
|
73
|
+
if (!tocNode) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const list = tocNode.querySelector("ol, ul");
|
|
77
|
+
return {
|
|
78
|
+
source: "nav",
|
|
79
|
+
items: list ? readNavList(list, navDocumentPath) : [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function readNavList(list, navDocumentPath) {
|
|
83
|
+
const items = [];
|
|
84
|
+
for (const child of Array.from(list.children)) {
|
|
85
|
+
if (child.tagName.toLowerCase() !== "li") {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const link = child.querySelector(":scope > a");
|
|
89
|
+
const labelNode = link ?? child.querySelector(":scope > span");
|
|
90
|
+
const nestedList = child.querySelector(":scope > ol, :scope > ul");
|
|
91
|
+
items.push({
|
|
92
|
+
label: labelNode?.textContent?.trim() ?? "",
|
|
93
|
+
href: resolveTocHref(navDocumentPath, link?.getAttribute("href")),
|
|
94
|
+
children: nestedList ? readNavList(nestedList, navDocumentPath) : [],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return items.filter((item) => item.label.length > 0);
|
|
98
|
+
}
|
|
99
|
+
async function parseNcxDocument(ncxPath, ncxDocumentPath, warnings) {
|
|
100
|
+
let ncxContent;
|
|
101
|
+
try {
|
|
102
|
+
ncxContent = await (0, promises_1.readFile)(ncxPath, "utf8");
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
warnings.add("TOC_NCX_UNREADABLE", `NCX TOC document could not be read; trying other TOC sources: ${ncxDocumentPath}`);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
parsed = xmlParser.parse(ncxContent);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
warnings.add("TOC_NCX_INVALID", `NCX TOC document could not be parsed; trying other TOC sources: ${ncxDocumentPath}`);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const navPoints = asArray(parsed.ncx?.navMap?.navPoint);
|
|
117
|
+
return {
|
|
118
|
+
source: "ncx",
|
|
119
|
+
items: navPoints.map((navPoint) => readNavPoint(navPoint, ncxDocumentPath)).filter((item) => item.label.length > 0),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function readNavPoint(navPoint, ncxDocumentPath) {
|
|
123
|
+
const label = readText(navPoint.navLabel) ?? "";
|
|
124
|
+
const href = resolveTocHref(ncxDocumentPath, readContentSource(navPoint.content));
|
|
125
|
+
return {
|
|
126
|
+
label,
|
|
127
|
+
href,
|
|
128
|
+
children: asArray(navPoint.navPoint).map((child) => readNavPoint(child, ncxDocumentPath)),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function resolveTocHref(baseDocumentPath, href) {
|
|
132
|
+
if (!href) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const resolved = (0, epub_path_1.resolveEpubHref)(baseDocumentPath, href);
|
|
136
|
+
return resolved.kind === "internal" ? resolved.targetKey : undefined;
|
|
137
|
+
}
|
|
138
|
+
function readText(value) {
|
|
139
|
+
if (!value || typeof value !== "object") {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
const textNode = value.text;
|
|
143
|
+
if (typeof textNode === "string") {
|
|
144
|
+
return textNode;
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(textNode)) {
|
|
147
|
+
const first = textNode.find((entry) => typeof entry === "string");
|
|
148
|
+
return typeof first === "string" ? first : undefined;
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
function readContentSource(value) {
|
|
153
|
+
if (!value || typeof value !== "object") {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const src = value.src;
|
|
157
|
+
return typeof src === "string" ? src : undefined;
|
|
158
|
+
}
|
|
159
|
+
function asArray(value) {
|
|
160
|
+
if (!value) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
return Array.isArray(value) ? value : [value];
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=toc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.js","sourceRoot":"","sources":["../../src/epub/toc.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConversionError = exports.convertEpub = void 0;
|
|
4
|
+
var convert_epub_1 = require("./application/convert-epub");
|
|
5
|
+
Object.defineProperty(exports, "convertEpub", { enumerable: true, get: function () { return convert_epub_1.convertEpub; } });
|
|
6
|
+
var errors_1 = require("./domain/errors");
|
|
7
|
+
Object.defineProperty(exports, "ConversionError", { enumerable: true, get: function () { return errors_1.ConversionError; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2DAAyD;AAAhD,2GAAA,WAAW,OAAA;AAEpB,0CAAkD;AAAzC,yGAAA,eAAe,OAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BookMetadata, TocItem } from "../domain/types";
|
|
2
|
+
export declare function renderFrontMatter(metadata: BookMetadata): string;
|
|
3
|
+
export declare function renderTopLevelTitle(metadata: BookMetadata): string;
|
|
4
|
+
export declare function renderToc(items: TocItem[]): string;
|
|
5
|
+
export declare function renderDocument(input: {
|
|
6
|
+
metadata: BookMetadata;
|
|
7
|
+
toc: TocItem[];
|
|
8
|
+
body: string;
|
|
9
|
+
}): string;
|