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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# mark-epub-down
|
|
2
|
+
|
|
3
|
+
Convert a single EPUB into a single Markdown source document for LLM knowledge bases, wikis, and related ingestion pipelines.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
This project focuses on producing semantically useful Markdown from EPUB input. The v1 goal is not visual EPUB reproduction. It prioritizes source order, document structure, TOC preservation, and conservative transformation rules.
|
|
8
|
+
|
|
9
|
+
## What v1 Does
|
|
10
|
+
|
|
11
|
+
- converts one EPUB into one Markdown file
|
|
12
|
+
- preserves spine order and source heading structure
|
|
13
|
+
- emits a dedicated `## TOC` section from EPUB-native TOC data
|
|
14
|
+
- includes minimal OPF-derived YAML front matter
|
|
15
|
+
- rewrites internal targets conservatively for merged single-file output
|
|
16
|
+
|
|
17
|
+
## What v1 Does Not Do
|
|
18
|
+
|
|
19
|
+
- visually reproduce EPUB layout or CSS
|
|
20
|
+
- guess missing structure aggressively
|
|
21
|
+
- optimize first for reader-specific Markdown rendering
|
|
22
|
+
- split output by chapter in the v1 baseline
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- Node.js `20`, `22`, or `24`
|
|
27
|
+
- npm
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Install the CLI globally:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g mark-epub-down
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or add the package to a Node.js project:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install mark-epub-down
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## CLI Usage
|
|
44
|
+
|
|
45
|
+
Convert an EPUB:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
epub2llm input.epub
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Write to an explicit output path:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
epub2llm input.epub -o output.md
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Run without global install:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx --package mark-epub-down epub2llm input.epub
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Show CLI help:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
epub2llm --help
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Existing output files are never overwritten silently. In an interactive terminal session, the CLI may ask for explicit overwrite confirmation with a default `No` answer.
|
|
70
|
+
|
|
71
|
+
## Node API
|
|
72
|
+
|
|
73
|
+
The published package currently exposes a CommonJS API:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const { convertEpub } = require("mark-epub-down");
|
|
77
|
+
|
|
78
|
+
(async () => {
|
|
79
|
+
const result = await convertEpub({
|
|
80
|
+
inputPath: "input.epub",
|
|
81
|
+
outputPath: "output.md",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
console.log(result.outputPath);
|
|
85
|
+
console.log(result.warnings);
|
|
86
|
+
})();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If the output path already exists, `convertEpub()` throws unless `overwrite: true` is passed:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
(async () => {
|
|
93
|
+
await convertEpub({
|
|
94
|
+
inputPath: "input.epub",
|
|
95
|
+
outputPath: "output.md",
|
|
96
|
+
overwrite: true,
|
|
97
|
+
});
|
|
98
|
+
})();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Output Shape
|
|
102
|
+
|
|
103
|
+
The generated Markdown follows this high-level structure:
|
|
104
|
+
|
|
105
|
+
```markdown
|
|
106
|
+
---
|
|
107
|
+
title: Example Book
|
|
108
|
+
creator: Example Author
|
|
109
|
+
language: en
|
|
110
|
+
published: 2026-04-09
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# Example Book
|
|
114
|
+
|
|
115
|
+
## TOC
|
|
116
|
+
|
|
117
|
+
- [Chapter 1](#...)
|
|
118
|
+
- Chapter 2
|
|
119
|
+
|
|
120
|
+
## Chapter 1
|
|
121
|
+
|
|
122
|
+
...
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Docs
|
|
126
|
+
|
|
127
|
+
- Public v1 spec: [docs/epub-to-md-v1-public-spec.md](https://github.com/thomson1973/mark-epub-down/blob/main/docs/epub-to-md-v1-public-spec.md)
|
|
128
|
+
- Technical selection notes: [docs/v1-technical-selection.md](https://github.com/thomson1973/mark-epub-down/blob/main/docs/v1-technical-selection.md)
|
|
129
|
+
|
|
130
|
+
## Limitations
|
|
131
|
+
|
|
132
|
+
- Fixed Layout EPUB (FXL) is out of scope for the v1 baseline
|
|
133
|
+
- some internal links or TOC targets may degrade to plain text when they cannot be rewritten safely
|
|
134
|
+
- complex tables may remain as HTML instead of being flattened into incorrect Markdown
|
|
135
|
+
- images and other high-confidence non-text media are removed by default in v1
|
|
136
|
+
- output files are never overwritten silently; interactive terminal use may ask for explicit confirmation
|
|
137
|
+
|
|
138
|
+
## Roadmap
|
|
139
|
+
|
|
140
|
+
- expand real-world sample coverage for malformed or inconsistent EPUB inputs
|
|
141
|
+
- refine deeper footnote and note-topology edge cases beyond explicit source anchors
|
|
142
|
+
- refine richer table fallback boundaries for more complex publisher markup
|
|
143
|
+
|
|
144
|
+
## Development
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm install
|
|
148
|
+
npm run build
|
|
149
|
+
npm run typecheck
|
|
150
|
+
npm test
|
|
151
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WarningRecord } from "../domain/types";
|
|
2
|
+
export interface ConvertEpubDocumentOptions {
|
|
3
|
+
inputPath: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ConvertEpubDocumentResult {
|
|
6
|
+
inputPath: string;
|
|
7
|
+
markdown: string;
|
|
8
|
+
warnings: WarningRecord[];
|
|
9
|
+
}
|
|
10
|
+
export declare function convertEpubDocument(options: ConvertEpubDocumentOptions): Promise<ConvertEpubDocumentResult>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertEpubDocument = convertEpubDocument;
|
|
4
|
+
const archive_1 = require("../epub/archive");
|
|
5
|
+
const content_1 = require("../epub/content");
|
|
6
|
+
const container_1 = require("../epub/container");
|
|
7
|
+
const opf_1 = require("../epub/opf");
|
|
8
|
+
const spine_1 = require("../epub/spine");
|
|
9
|
+
const toc_1 = require("../epub/toc");
|
|
10
|
+
const warnings_1 = require("../domain/warnings");
|
|
11
|
+
const render_1 = require("../output/render");
|
|
12
|
+
const cleanup_1 = require("../transform/cleanup");
|
|
13
|
+
const links_1 = require("../transform/links");
|
|
14
|
+
const markdown_1 = require("../transform/markdown");
|
|
15
|
+
const tables_1 = require("../transform/tables");
|
|
16
|
+
const errors_1 = require("../domain/errors");
|
|
17
|
+
async function convertEpubDocument(options) {
|
|
18
|
+
const warnings = new warnings_1.WarningCollector();
|
|
19
|
+
const workingDirectory = await (0, archive_1.createWorkingDirectory)();
|
|
20
|
+
try {
|
|
21
|
+
await (0, archive_1.extractArchive)(options.inputPath, workingDirectory);
|
|
22
|
+
const container = await (0, container_1.parseContainerDocument)(workingDirectory);
|
|
23
|
+
const packageDocument = await (0, opf_1.parsePackageDocument)(workingDirectory, container.opfPath);
|
|
24
|
+
const toc = await (0, toc_1.parseTocDocument)(workingDirectory, packageDocument, warnings);
|
|
25
|
+
const spineDocuments = (0, spine_1.buildSpineIndex)(packageDocument);
|
|
26
|
+
const loadedDocuments = await (0, content_1.loadSpineDocuments)(workingDirectory, spineDocuments);
|
|
27
|
+
for (const loadedDocument of loadedDocuments) {
|
|
28
|
+
const cleanup = (0, cleanup_1.cleanXhtmlDocument)(loadedDocument.dom.window.document);
|
|
29
|
+
if (cleanup.removedTags.length > 0) {
|
|
30
|
+
const uniqueTags = [...new Set(cleanup.removedTags)].join(", ");
|
|
31
|
+
warnings.add("ELEMENTS_DROPPED", `dropped non-text elements from ${loadedDocument.spineDocument.relativePath}: ${uniqueTags}`);
|
|
32
|
+
}
|
|
33
|
+
const tableResult = (0, tables_1.processTables)(loadedDocument.dom.window.document);
|
|
34
|
+
if (tableResult.complexTableCount > 0) {
|
|
35
|
+
const noun = tableResult.complexTableCount === 1 ? "table" : "tables";
|
|
36
|
+
warnings.add("COMPLEX_TABLE_PRESERVED", `preserved ${tableResult.complexTableCount} complex ${noun} as HTML because Markdown conversion would be lossy: ${loadedDocument.spineDocument.relativePath}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const anchorMap = (0, links_1.buildAnchorMap)(loadedDocuments.map((loadedDocument) => ({
|
|
40
|
+
idref: loadedDocument.spineDocument.idref,
|
|
41
|
+
relativePath: loadedDocument.spineDocument.relativePath,
|
|
42
|
+
document: loadedDocument.dom.window.document,
|
|
43
|
+
})), warnings);
|
|
44
|
+
for (const loadedDocument of loadedDocuments) {
|
|
45
|
+
(0, links_1.rewriteInternalLinks)(loadedDocument.dom.window.document, loadedDocument.spineDocument.relativePath, anchorMap, warnings);
|
|
46
|
+
(0, links_1.injectAnchorTargets)({
|
|
47
|
+
idref: loadedDocument.spineDocument.idref,
|
|
48
|
+
relativePath: loadedDocument.spineDocument.relativePath,
|
|
49
|
+
document: loadedDocument.dom.window.document,
|
|
50
|
+
}, anchorMap);
|
|
51
|
+
}
|
|
52
|
+
const rewrittenToc = (0, links_1.rewriteTocTargets)(toc.items, anchorMap, warnings);
|
|
53
|
+
const markdownConverter = (0, markdown_1.createMarkdownConverter)();
|
|
54
|
+
const body = loadedDocuments
|
|
55
|
+
.filter((loadedDocument) => loadedDocument.spineDocument.linear)
|
|
56
|
+
.map((loadedDocument) => {
|
|
57
|
+
const html = loadedDocument.dom.window.document.body?.innerHTML;
|
|
58
|
+
if (!html) {
|
|
59
|
+
throw errors_1.ConversionError.fatal("CONTENT_BODY_MISSING", `spine content document is missing a body element: ${loadedDocument.spineDocument.relativePath}`);
|
|
60
|
+
}
|
|
61
|
+
return markdownConverter.turndown(html).trim();
|
|
62
|
+
})
|
|
63
|
+
.filter((fragment) => fragment.length > 0)
|
|
64
|
+
.join("\n\n");
|
|
65
|
+
const markdown = (0, render_1.renderDocument)({
|
|
66
|
+
metadata: packageDocument.metadata,
|
|
67
|
+
toc: rewrittenToc,
|
|
68
|
+
body,
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
inputPath: options.inputPath,
|
|
72
|
+
markdown,
|
|
73
|
+
warnings: warnings.list(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
await (0, archive_1.cleanupWorkingDirectory)(workingDirectory);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=convert-epub-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert-epub-document.js","sourceRoot":"","sources":["../../src/application/convert-epub-document.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WarningRecord } from "../domain/types";
|
|
2
|
+
export interface ConvertEpubOptions {
|
|
3
|
+
inputPath: string;
|
|
4
|
+
outputPath?: string;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
overwrite?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ConvertEpubResult {
|
|
9
|
+
inputPath: string;
|
|
10
|
+
outputPath: string;
|
|
11
|
+
warnings: WarningRecord[];
|
|
12
|
+
}
|
|
13
|
+
export declare function convertEpub(options: ConvertEpubOptions): Promise<ConvertEpubResult>;
|
|
@@ -0,0 +1,35 @@
|
|
|
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.convertEpub = convertEpub;
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const convert_epub_document_1 = require("./convert-epub-document");
|
|
10
|
+
const errors_1 = require("../domain/errors");
|
|
11
|
+
const path_1 = require("../utils/path");
|
|
12
|
+
async function convertEpub(options) {
|
|
13
|
+
const cwd = options.cwd ?? process.cwd();
|
|
14
|
+
const inputPath = node_path_1.default.resolve(cwd, options.inputPath);
|
|
15
|
+
const outputPath = (0, path_1.deriveOutputPath)(inputPath, options.outputPath, cwd);
|
|
16
|
+
await assertInputExists(inputPath);
|
|
17
|
+
await (0, path_1.ensureOutputPathAvailable)(outputPath, options.overwrite === true);
|
|
18
|
+
const result = await (0, convert_epub_document_1.convertEpubDocument)({ inputPath });
|
|
19
|
+
await (0, promises_1.mkdir)(node_path_1.default.dirname(outputPath), { recursive: true });
|
|
20
|
+
await (0, promises_1.writeFile)(outputPath, result.markdown, "utf8");
|
|
21
|
+
return {
|
|
22
|
+
inputPath: result.inputPath,
|
|
23
|
+
outputPath,
|
|
24
|
+
warnings: result.warnings,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async function assertInputExists(inputPath) {
|
|
28
|
+
try {
|
|
29
|
+
await (0, promises_1.access)(inputPath);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw errors_1.ConversionError.fatal("INPUT_NOT_FOUND", `input EPUB does not exist: ${inputPath}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=convert-epub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert-epub.js","sourceRoot":"","sources":["../../src/application/convert-epub.ts"],"names":[],"mappings":";;;;;AAqBA,kCAkBC;AAvCD,+CAA4D;AAC5D,0DAA6B;AAE7B,mEAA8D;AAC9D,6CAAmD;AAEnD,wCAA4E;AAerE,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,mBAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,IAAA,uBAAgB,EAAC,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAExE,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,IAAA,gCAAyB,EAAC,UAAU,EAAE,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;IAExE,MAAM,MAAM,GAAG,MAAM,IAAA,2CAAmB,EAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IAExD,MAAM,IAAA,gBAAK,EAAC,mBAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,IAAA,oBAAS,EAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAErD,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU;QACV,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IAChD,IAAI,CAAC;QACH,MAAM,IAAA,iBAAM,EAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,wBAAe,CAAC,KAAK,CACzB,iBAAiB,EACjB,8BAA8B,SAAS,EAAE,CAC1C,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function confirmOverwrite(outputPath: string, stdin: NodeJS.ReadableStream, stderr: NodeJS.WritableStream): Promise<boolean>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.confirmOverwrite = confirmOverwrite;
|
|
4
|
+
async function confirmOverwrite(outputPath, stdin, stderr) {
|
|
5
|
+
stderr.write(`overwrite existing output file? ${outputPath} (y/N) `);
|
|
6
|
+
try {
|
|
7
|
+
const answer = await readSingleLine(stdin);
|
|
8
|
+
return answer !== null && isAffirmativeAnswer(answer);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function isAffirmativeAnswer(value) {
|
|
15
|
+
const normalized = value.trim().toLowerCase();
|
|
16
|
+
return normalized === "y" || normalized === "yes";
|
|
17
|
+
}
|
|
18
|
+
async function readSingleLine(stdin) {
|
|
19
|
+
let buffered = "";
|
|
20
|
+
for await (const chunk of stdin) {
|
|
21
|
+
buffered += chunk.toString();
|
|
22
|
+
const newlineIndex = buffered.indexOf("\n");
|
|
23
|
+
if (newlineIndex >= 0) {
|
|
24
|
+
return buffered.slice(0, newlineIndex).replace(/\r$/, "");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return buffered.length > 0 ? buffered.replace(/\r$/, "") : null;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=confirm-overwrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-overwrite.js","sourceRoot":"","sources":["../../src/cli/confirm-overwrite.ts"],"names":[],"mappings":";;AAAA,4CAaC;AAbM,KAAK,UAAU,gBAAgB,CACpC,UAAkB,EAClB,KAA4B,EAC5B,MAA6B;IAE7B,MAAM,CAAC,KAAK,CAAC,mCAAmC,UAAU,SAAS,CAAC,CAAC;IAErE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;QAC3C,OAAO,MAAM,KAAK,IAAI,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,OAAO,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,KAAK,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,KAA4B;IACxD,IAAI,QAAQ,GAAG,EAAE,CAAC;IAElB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,KAAuC,EAAE,CAAC;QAClE,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAE7B,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ConvertEpubResult } from "../application/convert-epub";
|
|
2
|
+
export declare function reportConversionResult(stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream, result: ConvertEpubResult): void;
|
|
3
|
+
export declare function reportCliError(stderr: NodeJS.WritableStream, message: string): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reportConversionResult = reportConversionResult;
|
|
4
|
+
exports.reportCliError = reportCliError;
|
|
5
|
+
const spec_1 = require("../domain/spec");
|
|
6
|
+
const warnings_1 = require("../domain/warnings");
|
|
7
|
+
function reportConversionResult(stdout, stderr, result) {
|
|
8
|
+
const cliWarnings = (0, warnings_1.summarizeWarnings)((0, warnings_1.getCliVisibleWarnings)(result.warnings));
|
|
9
|
+
emitWarnings(stderr, cliWarnings);
|
|
10
|
+
emitSuccess(stdout, result.outputPath, cliWarnings.length);
|
|
11
|
+
}
|
|
12
|
+
function reportCliError(stderr, message) {
|
|
13
|
+
stderr.write(`${spec_1.CLI_BINARY_NAME}: ${message}\n`);
|
|
14
|
+
}
|
|
15
|
+
function emitWarnings(stderr, warnings) {
|
|
16
|
+
for (const warning of warnings) {
|
|
17
|
+
stderr.write(`warning [${warning.code}]: ${warning.message}\n`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function emitSuccess(stdout, outputPath, warningCount) {
|
|
21
|
+
const suffix = warningCount > 0 ? ` (${warningCount === 1 ? "1 warning" : `${warningCount} warnings`})` : "";
|
|
22
|
+
stdout.write(`wrote ${outputPath}${suffix}\n`);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=reporting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporting.js","sourceRoot":"","sources":["../../src/cli/reporting.ts"],"names":[],"mappings":";;AAKA,wDAQC;AAED,wCAEC;AAhBD,yCAAiD;AAEjD,iDAA8E;AAE9E,SAAgB,sBAAsB,CACpC,MAA6B,EAC7B,MAA6B,EAC7B,MAAyB;IAEzB,MAAM,WAAW,GAAG,IAAA,4BAAiB,EAAC,IAAA,gCAAqB,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9E,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAClC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED,SAAgB,cAAc,CAAC,MAA6B,EAAE,OAAe;IAC3E,MAAM,CAAC,KAAK,CAAC,GAAG,sBAAe,KAAK,OAAO,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,MAA6B,EAAE,QAAyB;IAC5E,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,KAAK,CAAC,YAAY,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAA6B,EAAE,UAAkB,EAAE,YAAoB;IAC1F,MAAM,MAAM,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7G,MAAM,CAAC,KAAK,CAAC,SAAS,UAAU,GAAG,MAAM,IAAI,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface RunConvertCommandContext {
|
|
2
|
+
cwd: string;
|
|
3
|
+
stdin: NodeJS.ReadableStream;
|
|
4
|
+
stdout: NodeJS.WritableStream;
|
|
5
|
+
stderr: NodeJS.WritableStream;
|
|
6
|
+
interactive: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function runConvertCommand(input: string, options: {
|
|
9
|
+
output?: string;
|
|
10
|
+
}, context: RunConvertCommandContext): Promise<number>;
|
|
@@ -0,0 +1,61 @@
|
|
|
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.runConvertCommand = runConvertCommand;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const convert_epub_1 = require("../application/convert-epub");
|
|
9
|
+
const errors_1 = require("../domain/errors");
|
|
10
|
+
const path_1 = require("../utils/path");
|
|
11
|
+
const confirm_overwrite_1 = require("./confirm-overwrite");
|
|
12
|
+
const reporting_1 = require("./reporting");
|
|
13
|
+
async function runConvertCommand(input, options, context) {
|
|
14
|
+
try {
|
|
15
|
+
const result = await (0, convert_epub_1.convertEpub)({
|
|
16
|
+
inputPath: input,
|
|
17
|
+
outputPath: options.output,
|
|
18
|
+
cwd: context.cwd,
|
|
19
|
+
});
|
|
20
|
+
(0, reporting_1.reportConversionResult)(context.stdout, context.stderr, result);
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (!(error instanceof errors_1.ConversionError)) {
|
|
25
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
26
|
+
(0, reporting_1.reportCliError)(context.stderr, `unexpected error: ${message}`);
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
if (error.code === "OUTPUT_EXISTS" && context.interactive) {
|
|
30
|
+
const inputPath = node_path_1.default.resolve(context.cwd, input);
|
|
31
|
+
const outputPath = (0, path_1.deriveOutputPath)(inputPath, options.output, context.cwd);
|
|
32
|
+
const confirmed = await (0, confirm_overwrite_1.confirmOverwrite)(outputPath, context.stdin, context.stderr);
|
|
33
|
+
if (confirmed) {
|
|
34
|
+
try {
|
|
35
|
+
const result = await (0, convert_epub_1.convertEpub)({
|
|
36
|
+
inputPath: input,
|
|
37
|
+
outputPath: options.output,
|
|
38
|
+
cwd: context.cwd,
|
|
39
|
+
overwrite: true,
|
|
40
|
+
});
|
|
41
|
+
(0, reporting_1.reportConversionResult)(context.stdout, context.stderr, result);
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
catch (retryError) {
|
|
45
|
+
if (retryError instanceof errors_1.ConversionError) {
|
|
46
|
+
(0, reporting_1.reportCliError)(context.stderr, retryError.message);
|
|
47
|
+
return retryError.exitCode;
|
|
48
|
+
}
|
|
49
|
+
const message = retryError instanceof Error ? retryError.message : String(retryError);
|
|
50
|
+
(0, reporting_1.reportCliError)(context.stderr, `unexpected error: ${message}`);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
(0, reporting_1.reportCliError)(context.stderr, `output file already exists and overwrite was not confirmed: ${outputPath}`);
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
(0, reporting_1.reportCliError)(context.stderr, error.message);
|
|
58
|
+
return error.exitCode;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=run-convert-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-convert-command.js","sourceRoot":"","sources":["../../src/cli/run-convert-command.ts"],"names":[],"mappings":";;;;;AAgBA,8CAwDC;AAxED,0DAA6B;AAE7B,8DAA0D;AAC1D,6CAAmD;AACnD,wCAAiD;AACjD,2DAAuD;AACvD,2CAAqE;AAU9D,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,OAA4B,EAC5B,OAAiC;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,0BAAW,EAAC;YAC/B,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,OAAO,CAAC,MAAM;YAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QACH,IAAA,kCAAsB,EAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,wBAAe,CAAC,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,IAAA,0BAAc,EAAC,OAAO,CAAC,MAAM,EAAE,qBAAqB,OAAO,EAAE,CAAC,CAAC;YAC/D,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAC1D,MAAM,SAAS,GAAG,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,UAAU,GAAG,IAAA,uBAAgB,EAAC,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAC5E,MAAM,SAAS,GAAG,MAAM,IAAA,oCAAgB,EAAC,UAAU,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACpF,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,IAAA,0BAAW,EAAC;wBAC/B,SAAS,EAAE,KAAK;wBAChB,UAAU,EAAE,OAAO,CAAC,MAAM;wBAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;wBAChB,SAAS,EAAE,IAAI;qBAChB,CAAC,CAAC;oBACH,IAAA,kCAAsB,EAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAC/D,OAAO,CAAC,CAAC;gBACX,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,IAAI,UAAU,YAAY,wBAAe,EAAE,CAAC;wBAC1C,IAAA,0BAAc,EAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;wBACnD,OAAO,UAAU,CAAC,QAAQ,CAAC;oBAC7B,CAAC;oBAED,MAAM,OAAO,GAAG,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;oBACtF,IAAA,0BAAc,EAAC,OAAO,CAAC,MAAM,EAAE,qBAAqB,OAAO,EAAE,CAAC,CAAC;oBAC/D,OAAO,CAAC,CAAC;gBACX,CAAC;YACH,CAAC;YAED,IAAA,0BAAc,EACZ,OAAO,CAAC,MAAM,EACd,+DAA+D,UAAU,EAAE,CAC5E,CAAC;YACF,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAA,0BAAc,EAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9C,OAAO,KAAK,CAAC,QAAQ,CAAC;IACxB,CAAC;AACH,CAAC"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const spec_1 = require("./domain/spec");
|
|
6
|
+
const run_convert_command_1 = require("./cli/run-convert-command");
|
|
7
|
+
async function main() {
|
|
8
|
+
const program = new commander_1.Command();
|
|
9
|
+
program
|
|
10
|
+
.name(spec_1.CLI_BINARY_NAME)
|
|
11
|
+
.description("Convert a single EPUB into a single Markdown source document.")
|
|
12
|
+
.version("0.1.0", "-V, --version", "output the version number")
|
|
13
|
+
.argument("<input>", "input EPUB file")
|
|
14
|
+
.option("-o, --output <path>", "output Markdown path")
|
|
15
|
+
.showHelpAfterError("(add -h for usage)")
|
|
16
|
+
.action(async (input, options) => {
|
|
17
|
+
process.exitCode = await (0, run_convert_command_1.runConvertCommand)(input, options, {
|
|
18
|
+
cwd: process.cwd(),
|
|
19
|
+
stdin: process.stdin,
|
|
20
|
+
stdout: process.stdout,
|
|
21
|
+
stderr: process.stderr,
|
|
22
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
await program.parseAsync(process.argv);
|
|
26
|
+
}
|
|
27
|
+
void main();
|
|
28
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AAEpC,wCAAgD;AAChD,mEAA8D;AAE9D,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,sBAAe,CAAC;SACrB,WAAW,CAAC,+DAA+D,CAAC;SAC5E,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,2BAA2B,CAAC;SAC9D,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;SACtC,MAAM,CAAC,qBAAqB,EAAE,sBAAsB,CAAC;SACrD,kBAAkB,CAAC,oBAAoB,CAAC;SACxC,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,OAA4B,EAAE,EAAE;QAC5D,OAAO,CAAC,QAAQ,GAAG,MAAM,IAAA,uCAAiB,EAAC,KAAK,EAAE,OAAO,EAAE;YACzD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;SAClE,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class ConversionError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly fatal: boolean;
|
|
4
|
+
readonly exitCode: number;
|
|
5
|
+
constructor(code: string, message: string, fatal?: boolean, exitCode?: number);
|
|
6
|
+
static fatal(code: string, message: string): ConversionError;
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConversionError = void 0;
|
|
4
|
+
class ConversionError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
fatal;
|
|
7
|
+
exitCode;
|
|
8
|
+
constructor(code, message, fatal = true, exitCode = 1) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "ConversionError";
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.fatal = fatal;
|
|
13
|
+
this.exitCode = exitCode;
|
|
14
|
+
}
|
|
15
|
+
static fatal(code, message) {
|
|
16
|
+
return new ConversionError(code, message, true, 1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ConversionError = ConversionError;
|
|
20
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/domain/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,eAAgB,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,KAAK,CAAU;IACf,QAAQ,CAAS;IAEjC,YAAmB,IAAY,EAAE,OAAe,EAAE,KAAK,GAAG,IAAI,EAAE,QAAQ,GAAG,CAAC;QAC1E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,IAAY,EAAE,OAAe;QAC/C,OAAO,IAAI,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;CACF;AAhBD,0CAgBC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const CLI_BINARY_NAME = "epub2llm";
|
|
2
|
+
export declare const GENERATED_TOC_HEADING = "TOC";
|
|
3
|
+
export declare const FRONT_MATTER_FIELDS: readonly ["title", "creator", "language", "identifier", "publisher", "published"];
|
|
4
|
+
export declare const REMOVABLE_TAGS: Set<string>;
|
|
5
|
+
export declare const NON_BLACKLISTED_STRUCTURAL_CONTAINERS: Set<string>;
|
|
6
|
+
export declare const NOTE_REFERENCE_TYPES: Set<string>;
|
|
7
|
+
export declare const NOTE_BODY_TYPES: Set<string>;
|
|
8
|
+
export declare const NOTE_BACKLINK_TYPES: Set<string>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NOTE_BACKLINK_TYPES = exports.NOTE_BODY_TYPES = exports.NOTE_REFERENCE_TYPES = exports.NON_BLACKLISTED_STRUCTURAL_CONTAINERS = exports.REMOVABLE_TAGS = exports.FRONT_MATTER_FIELDS = exports.GENERATED_TOC_HEADING = exports.CLI_BINARY_NAME = void 0;
|
|
4
|
+
exports.CLI_BINARY_NAME = "epub2llm";
|
|
5
|
+
exports.GENERATED_TOC_HEADING = "TOC";
|
|
6
|
+
exports.FRONT_MATTER_FIELDS = [
|
|
7
|
+
"title",
|
|
8
|
+
"creator",
|
|
9
|
+
"language",
|
|
10
|
+
"identifier",
|
|
11
|
+
"publisher",
|
|
12
|
+
"published",
|
|
13
|
+
];
|
|
14
|
+
exports.REMOVABLE_TAGS = new Set([
|
|
15
|
+
"script",
|
|
16
|
+
"style",
|
|
17
|
+
"img",
|
|
18
|
+
"svg",
|
|
19
|
+
"canvas",
|
|
20
|
+
"audio",
|
|
21
|
+
"video",
|
|
22
|
+
"source",
|
|
23
|
+
"track",
|
|
24
|
+
"iframe",
|
|
25
|
+
"object",
|
|
26
|
+
"embed",
|
|
27
|
+
"form",
|
|
28
|
+
"input",
|
|
29
|
+
"button",
|
|
30
|
+
"select",
|
|
31
|
+
"option",
|
|
32
|
+
"textarea",
|
|
33
|
+
"meta",
|
|
34
|
+
"link",
|
|
35
|
+
"noscript",
|
|
36
|
+
]);
|
|
37
|
+
exports.NON_BLACKLISTED_STRUCTURAL_CONTAINERS = new Set([
|
|
38
|
+
"figure",
|
|
39
|
+
"figcaption",
|
|
40
|
+
"aside",
|
|
41
|
+
"section",
|
|
42
|
+
"nav",
|
|
43
|
+
"div",
|
|
44
|
+
"span",
|
|
45
|
+
]);
|
|
46
|
+
exports.NOTE_REFERENCE_TYPES = new Set(["noteref"]);
|
|
47
|
+
exports.NOTE_BODY_TYPES = new Set(["footnote", "endnote", "rearnote"]);
|
|
48
|
+
exports.NOTE_BACKLINK_TYPES = new Set(["backlink"]);
|
|
49
|
+
//# sourceMappingURL=spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/domain/spec.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG,UAAU,CAAC;AAC7B,QAAA,qBAAqB,GAAG,KAAK,CAAC;AAE9B,QAAA,mBAAmB,GAAG;IACjC,OAAO;IACP,SAAS;IACT,UAAU;IACV,YAAY;IACZ,WAAW;IACX,WAAW;CACH,CAAC;AAEE,QAAA,cAAc,GAAG,IAAI,GAAG,CAAC;IACpC,QAAQ;IACR,OAAO;IACP,KAAK;IACL,KAAK;IACL,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;IACN,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,MAAM;IACN,MAAM;IACN,UAAU;CACX,CAAC,CAAC;AAEU,QAAA,qCAAqC,GAAG,IAAI,GAAG,CAAC;IAC3D,QAAQ;IACR,YAAY;IACZ,OAAO;IACP,SAAS;IACT,KAAK;IACL,KAAK;IACL,MAAM;CACP,CAAC,CAAC;AAEU,QAAA,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5C,QAAA,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;AAC/D,QAAA,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC"}
|