Initial commit

This commit is contained in:
qwsdcvghyu89
2026-06-17 07:19:25 +10:00
commit 363d894c79
26 changed files with 1805 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
import { readFileSync } from 'fs';
import path from 'path';
import type { ChapterView } from '../types.ts';
const TEMPLATE_PATH = path.resolve(process.cwd(), 'templates', 'book.template.html');
let templateCache: string | null = null;
function getTemplate(): string {
if (!templateCache) templateCache = readFileSync(TEMPLATE_PATH, 'utf-8');
return templateCache;
}
function escapeHtml(text: string): string {
return text
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function readChapterLines(filePath: string): string[] {
try {
const raw = readFileSync(filePath, 'utf-8');
// Both plain-text and JSON chapters are read as plain text for HTML output,
// matching the C# SomeBasicFileView.GetAsHTML() behaviour.
try {
const fragments = JSON.parse(raw) as Array<{ body: string }>;
if (Array.isArray(fragments) && fragments.length > 0 && 'body' in (fragments[0] ?? {})) {
return fragments.map(f => f.body).filter(Boolean);
}
} catch {
// not JSON — fall through to plain text
}
return raw.split(/[\n\r]+/).map(l => l.trim()).filter(Boolean);
} catch {
return [];
}
}
export function renderHtml(view: ChapterView): string {
const template = getTemplate();
const content = view.chapters
.map((chapter, i) => {
const chapNum = view.min + i;
const lines = readChapterLines(chapter.path);
if (lines.length === 0) return '';
const paragraphs = lines
.map((line, j) => ` <p id="para${chapNum}-${j}">${escapeHtml(line)}</p>`)
.join('\n');
return `<div id="chap${chapNum}">\n${paragraphs}\n</div>`;
})
.filter(Boolean)
.join('\n');
return template
.replace('{id}', String(view.id))
.replace('{min}', String(view.min))
.replace('{max}', String(view.max))
.replace('{content}', content);
}
+27
View File
@@ -0,0 +1,27 @@
import { readFileSync } from 'fs';
import type { ChapterView, TextFragment } from '../types.ts';
interface ChapterRow {
chapter: number;
contents: string[] | TextFragment[];
}
function readChapterContents(filePath: string, hasStyle: boolean): string[] | TextFragment[] {
try {
const raw = readFileSync(filePath, 'utf-8');
if (hasStyle) {
return JSON.parse(raw) as TextFragment[];
}
return raw.split(/[\n\r]+/).map(l => l.trim()).filter(Boolean);
} catch {
return [];
}
}
export function renderJson(view: ChapterView): string {
const rows: ChapterRow[] = view.chapters.map((chapter, i) => ({
chapter: view.min + i,
contents: readChapterContents(chapter.path, chapter.hasStyle),
}));
return JSON.stringify(rows);
}