buildSearchIndex function
Future<SearchIndexBuild>
buildSearchIndex(})
Walks contentDir for .md files and builds a SearchIndexBuild.
routeOfmaps a file to its site route. Defaults to the conventioncontent/a/b.md->/a/b, withindex.mdmapping to its parent directory — see md.routeFor.groupFor,titleForanddescriptionForread a route (and, for the latter two, the page's own front matter) to fill in the fields a search result shows. All optional: a site that doesn't group pages, or has no per-page description, can skip them.compareorders the final doc list. Left unset, docs stay in the order files were found (alphabetical by path). Passing one that reflects a site's own reading order — sidebar order, say — means that, all else equal in the ranking, earlier pages in that order win ties.maxSectionLengthcaps how much of each section's body is kept, since the whole index downloads at once.
Implementation
Future<SearchIndexBuild> buildSearchIndex(
Directory contentDir, {
String Function(File file, String contentPath)? routeOf,
String Function(String route)? groupFor,
String Function(String route, Map<String, String> frontMatter)? titleFor,
String Function(String route, Map<String, String> frontMatter)?
descriptionFor,
int Function(SearchDoc a, SearchDoc b)? compare,
int maxSectionLength = 1200,
}) async {
if (!contentDir.existsSync()) {
throw ContentDirectoryNotFoundException(contentDir.path);
}
routeOf ??= (file, contentPath) => md.routeFor(file.path, contentPath);
groupFor ??= (_) => '';
titleFor ??= (route, frontMatter) => frontMatter['title'] ?? route;
descriptionFor ??= (route, frontMatter) => frontMatter['description'] ?? '';
final files =
contentDir
.listSync(recursive: true)
.whereType<File>()
.where((file) => file.path.endsWith('.md'))
.toList()
..sort((a, b) => a.path.compareTo(b.path));
final docs = <SearchDoc>[];
for (final file in files) {
final route = routeOf(file, contentDir.path);
final raw = await file.readAsString();
final (:frontMatter, :body) = md.splitFrontMatter(raw);
docs.add(
SearchDoc(
url: route,
title: titleFor(route, frontMatter),
description: descriptionFor(route, frontMatter),
group: groupFor(route),
sections: [
for (final section in md.sectionsOf(
body,
maxSectionLength: maxSectionLength,
))
SearchSection(
heading: section['h'] as String?,
anchor: section['a'] as String?,
body: section['b'] as String? ?? '',
),
],
),
);
}
if (compare != null) docs.sort(compare);
final json =
'${const JsonEncoder.withIndent(' ').convert({
'v': 1,
'docs': [for (final doc in docs) doc.toJson()],
})}\n';
return SearchIndexBuild(docs: docs, json: json);
}