blob: d82139cb7f1a5ef0ba3a1a2d47529441305a993a [file]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:path/path.dart' as p;
import 'utils.dart';
class HtmlTemplate {
static Future<HtmlTemplate> createDefault() async {
final htmlData = await loadResourceDataAsString('index.html');
return HtmlTemplate._(htmlData);
}
final String htmlTemplateData;
HtmlTemplate._(this.htmlTemplateData) {
_parseTemplate();
}
Future<void> generateStaticResources(Directory outDir, {Stats? stats}) async {
const resources = [
'script.js',
'styles.css',
'styles-dark.css',
'styles-light.css',
'toggle-dark.svg',
'toggle-light.svg',
];
for (var resource in resources) {
final file = File(p.join(outDir.path, '_resources', resource));
if (!file.parent.existsSync()) {
file.parent.createSync(recursive: true);
}
var data = await loadResourceDataAsBytes(resource);
file.writeAsBytesSync(data);
stats?.genFile(file);
}
}
String templateSubtitute({
required String pageTitle,
required String pathPrefix,
required String pageRef,
String navbar = '',
String breadcrumbs = '',
String pageContent = '',
String toc = '',
String footer = '',
}) {
final subs = {
'page-title': pageTitle,
'prefix': pathPrefix,
'pageRef': pageRef,
'navbar': navbar,
'breadcrumbs': breadcrumbs,
'page-content': pageContent,
'toc': toc,
'footer': footer,
};
var results = _generateString(subs);
return results;
}
late final List<_Location> _locations;
void _parseTemplate() {
final regex = RegExp(r'{{\s+([\w-]+)\s+}}');
var results = <_Location>[];
for (var match in regex.allMatches(htmlTemplateData)) {
results.add(_Location(match.start, match.end, match.group(1)!));
}
_locations = results.toList();
}
String _generateString(Map<String, String> subs) {
var buf = StringBuffer();
var offset = 0;
for (var loc in _locations) {
if (offset < loc.start) {
buf.write(htmlTemplateData.substring(offset, loc.start));
offset = loc.start;
}
buf.write(subs[loc.id]!);
offset = loc.end;
}
if (offset < htmlTemplateData.length) {
buf.write(htmlTemplateData.substring(offset));
}
return buf.toString();
}
}
class _Location {
final int start;
final int end;
final String id;
_Location(this.start, this.end, this.id);
@override
String toString() => '$id $start $end';
}
Future<String> loadResourceDataAsString(String name) async {
var packageUri = Uri.parse('package:jot/resources/$name');
var fileUri = await Isolate.resolvePackageUri(packageUri);
return File(fileUri!.toFilePath()).readAsStringSync();
}
Future<Uint8List> loadResourceDataAsBytes(String name) async {
var packageUri = Uri.parse('package:jot/resources/$name');
var fileUri = await Isolate.resolvePackageUri(packageUri);
return File(fileUri!.toFilePath()).readAsBytesSync();
}