decodeBookDocument function
Rebuilds a BookDocument from json and the images its references
name.
Returns null in exactly three cases: unreadable json, a schema-version
mismatch, or an unresolved image reference. An unresolved reference is
a decode failure, not a hole — the default empty images map exists
for documents that have no images, not as a way to restore an illustrated
book without its pictures.
Pass the same segmenter the document was parsed with. Omitted, the
default is seeded from the decoded metadata's language — the same seeding
parse performs — so the default-to-default round trip segments
identically by construction.
Implementation
BookDocument? decodeBookDocument(
Map<String, dynamic> json, {
Map<String, ImageData> images = const {},
TextSegmenter? segmenter,
}) {
try {
if (json['v'] != kBookDocumentSchemaVersion) return null;
final metaJson = json['metadata'] as Map<String, dynamic>;
final lang = metaJson['lang'] as String;
final effectiveSegmenter =
segmenter ?? RuleBasedSegmenter(languageCode: lang);
final coverJson = metaJson['cover'] as Map<String, dynamic>?;
final metadata = BookMetadata(
title: metaJson['title'] as String?,
authors: (metaJson['authors'] as List).cast<String>(),
sourceLanguageCode: lang,
cover: coverJson == null ? null : _resolveImage(coverJson, images),
);
final chapters = <Chapter>[];
for (final chapterJson
in (json['chapters'] as List).cast<Map<String, dynamic>>()) {
chapters.add(Chapter(
index: chapters.length,
title: chapterJson['title'] as String?,
level: chapterJson['level'] as int,
blocks: [
for (final blockJson
in (chapterJson['blocks'] as List).cast<Map<String, dynamic>>())
_blockFromJson(blockJson, images, effectiveSegmenter),
],
));
}
return BookDocument(metadata: metadata, chapters: chapters);
} catch (_) {
return null;
}
}