55library dartdoc.templates;
66
77import 'dart:async' show Future;
8- import 'dart:io' show File;
8+ import 'dart:io' show File, Directory ;
99
10+ import 'package:dartdoc/dartdoc.dart' ;
1011import 'package:dartdoc/src/html/resource_loader.dart' as loader;
1112import 'package:mustache/mustache.dart' ;
13+ import 'package:path/path.dart' as path;
1214
1315const _partials = < String > [
1416 'callable' ,
@@ -36,50 +38,104 @@ const _partials = <String>[
3638 'accessor_setter' ,
3739];
3840
39- Future <Map <String , String >> _loadPartials (List <String > headerPaths,
40- List <String > footerPaths, List <String > footerTextPaths) async {
41- final String headerPlaceholder = '<!-- header placeholder -->' ;
42- final String footerPlaceholder = '<!-- footer placeholder -->' ;
43- final String footerTextPlaceholder = '<!-- footer-text placeholder -->' ;
41+ const _requiredTemplates = < String > [
42+ '404error.html' ,
43+ 'category.html' ,
44+ 'class.html' ,
45+ 'constant.html' ,
46+ 'constructor.html' ,
47+ 'enum.html' ,
48+ 'function.html' ,
49+ 'index.html' ,
50+ 'library.html' ,
51+ 'method.html' ,
52+ 'mixin.html' ,
53+ 'property.html' ,
54+ 'top_level_constant.html' ,
55+ 'top_level_property.html' ,
56+ 'typedef.html' ,
57+ ];
58+
59+ const String _headerPlaceholder = '<!-- header placeholder -->' ;
60+ const String _footerPlaceholder = '<!-- footer placeholder -->' ;
61+ const String _footerTextPlaceholder = '<!-- footer-text placeholder -->' ;
62+
63+ Future <Map <String , String >> _loadPartials (
64+ _TemplatesLoader templatesLoader,
65+ List <String > headerPaths,
66+ List <String > footerPaths,
67+ List <String > footerTextPaths) async {
4468
4569 headerPaths ?? = [];
4670 footerPaths ?? = [];
4771 footerTextPaths ?? = [];
4872
49- var partials = < String , String > {} ;
73+ var partials = await templatesLoader. loadPartials () ;
5074
51- Future < String > _loadPartial (String templatePath) async {
52- String template = await _getTemplateFile (templatePath) ;
53-
54- if (templatePath. contains ( '_head' )) {
55- String headerValue =
56- headerPaths. map ((path) => File (path). readAsStringSync ()). join ( ' \n ' );
57- template = template. replaceAll (headerPlaceholder, headerValue) ;
75+ void replacePlaceholder (String key, String placeholder, List < String > paths) {
76+ var template = partials[key] ;
77+ if (template != null && paths != null && paths.isNotEmpty) {
78+ String replacement = paths. map ((p) => File (p). readAsStringSync ())
79+ . join ( ' \n ' );
80+ template = template. replaceAll (placeholder, replacement );
81+ partials[key] = template;
5882 }
83+ }
5984
60- if (templatePath.contains ('_footer' )) {
61- String footerValue =
62- footerPaths.map ((path) => File (path).readAsStringSync ()).join ('\n ' );
63- template = template.replaceAll (footerPlaceholder, footerValue);
85+ replacePlaceholder ('head' , _headerPlaceholder, headerPaths);
86+ replacePlaceholder ('footer' , _footerPlaceholder, footerPaths);
87+ replacePlaceholder ('footer' , _footerTextPlaceholder, footerTextPaths);
6488
65- String footerTextValue = footerTextPaths
66- .map ((path) => File (path).readAsStringSync ())
67- .join ('\n ' );
68- template = template.replaceAll (footerTextPlaceholder, footerTextValue);
69- }
89+ return partials;
90+ }
7091
71- return template;
72- }
92+ abstract class _TemplatesLoader {
93+ Future <Map <String , String >> loadPartials ();
94+ Future <String > loadTemplate (String name);
95+ }
7396
74- for (String partial in _partials) {
75- partials[partial] = await _loadPartial ('_$partial .html' );
97+ class _DefaultTemplatesLoader extends _TemplatesLoader {
98+ @override
99+ Future <Map <String , String >> loadPartials () async {
100+ var partials = < String , String > {};
101+ for (String partial in _partials) {
102+ var uri = 'package:dartdoc/templates/_$partial .html' ;
103+ partials[partial] = await loader.loadAsString (uri);
104+ }
105+ return partials;
76106 }
77107
78- return partials;
108+ @override
109+ Future <String > loadTemplate (String name) =>
110+ loader.loadAsString ('package:dartdoc/templates/$name ' );
79111}
80112
81- Future <String > _getTemplateFile (String templateFileName) =>
82- loader.loadAsString ('package:dartdoc/templates/$templateFileName ' );
113+ class _DirectoryTemplatesLoader extends _TemplatesLoader {
114+ final Directory _directory;
115+
116+ _DirectoryTemplatesLoader (this ._directory);
117+
118+ @override
119+ Future <Map <String , String >> loadPartials () async {
120+ var partials = < String , String > {};
121+
122+ for (File file in _directory.listSync ().whereType <File >()) {
123+ var basename = path.basename (file.path);
124+ if (basename.startsWith ('_' ) && basename.endsWith ('.html' )) {
125+ var content = file.readAsString ();
126+ var partialName = basename.substring (1 , basename.lastIndexOf ('.' ));
127+ partials[partialName] = await content;
128+ }
129+ }
130+ return partials;
131+ }
132+
133+ @override
134+ Future <String > loadTemplate (String name) {
135+ var file = File (path.join (_directory.path, name));
136+ return file.readAsString ();
137+ }
138+ }
83139
84140class Templates {
85141 final Template categoryTemplate;
@@ -98,12 +154,44 @@ class Templates {
98154 final Template topLevelPropertyTemplate;
99155 final Template typeDefTemplate;
100156
101- static Future <Templates > create (
157+ static Future <Templates > createDefault (
158+ {List <String > headerPaths,
159+ List <String > footerPaths,
160+ List <String > footerTextPaths}) async {
161+ return _create (_DefaultTemplatesLoader (),
162+ headerPaths: headerPaths,
163+ footerPaths: footerPaths,
164+ footerTextPaths: footerTextPaths);
165+ }
166+
167+ static Future <Templates > fromDirectory (
168+ Directory dir,
169+ {List <String > headerPaths,
170+ List <String > footerPaths,
171+ List <String > footerTextPaths}) async {
172+ await _checkRequiredTemplatesExist (dir);
173+ return _create (_DirectoryTemplatesLoader (dir),
174+ headerPaths: headerPaths,
175+ footerPaths: footerPaths,
176+ footerTextPaths: footerTextPaths);
177+ }
178+
179+ static void _checkRequiredTemplatesExist (Directory dir) {
180+ for (var name in _requiredTemplates) {
181+ var file = File (path.join (dir.path, name));
182+ if (! file.existsSync ()) {
183+ throw DartdocFailure ('Missing required template file: "$name "' );
184+ }
185+ }
186+ }
187+
188+ static Future <Templates > _create (
189+ _TemplatesLoader templatesLoader,
102190 {List <String > headerPaths,
103191 List <String > footerPaths,
104192 List <String > footerTextPaths}) async {
105193 var partials =
106- await _loadPartials (headerPaths, footerPaths, footerTextPaths);
194+ await _loadPartials (templatesLoader, headerPaths, footerPaths, footerTextPaths);
107195
108196 Template _partial (String name) {
109197 String partial = partials[name];
@@ -114,7 +202,7 @@ class Templates {
114202 }
115203
116204 Future <Template > _loadTemplate (String templatePath) async {
117- String templateContents = await _getTemplateFile (templatePath);
205+ String templateContents = await templatesLoader. loadTemplate (templatePath);
118206 return Template (templateContents, partialResolver: _partial);
119207 }
120208
0 commit comments