Skip to content

Commit e466c51

Browse files
committed
Extract a FileWriter typedef and make it a parameter to HtmlGeneratorInstance
Logic for writing all files is moved into HtmlGenerator Eliminates written-file tracking from HtmlGeneatorInstance
1 parent cc9b95a commit e466c51

File tree

2 files changed

+53
-51
lines changed

2 files changed

+53
-51
lines changed

lib/src/html/html_generator.dart

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ library dartdoc.html_generator;
77
import 'dart:async' show Future, StreamController, Stream;
88
import 'dart:io' show File;
99

10+
import 'package:path/path.dart' as p;
11+
1012
import '../generator.dart';
1113
import '../model.dart';
1214
import 'html_generator_instance.dart';
@@ -44,7 +46,7 @@ class HtmlGenerator extends Generator {
4446
Stream<File> get onFileCreated => _onFileCreated.stream;
4547

4648
@override
47-
Set<String> get writtenFiles => _instance.writtenFiles;
49+
final Set<String> writtenFiles = new Set<String>();
4850

4951
static Future<HtmlGenerator> create(
5052
{HtmlGeneratorOptions options,
@@ -66,11 +68,44 @@ class HtmlGenerator extends Generator {
6668

6769
/// Actually write out the documentation for [package].
6870
/// Stores the HtmlGeneratorInstance so we can access it in [writtenFiles].
69-
Future generate(Package package, String outputDirectoryPath) {
71+
Future generate(Package package, String outputDirectoryPath) async {
7072
assert(_instance == null);
71-
_instance = new HtmlGeneratorInstance(
72-
_options, _templates, package, outputDirectoryPath, _onFileCreated);
73-
return _instance.generate();
73+
74+
var enabled = true;
75+
void write(String filePath, Object content, {bool allowOverwrite}) {
76+
allowOverwrite ??= false;
77+
if (!enabled) {
78+
throw new StateError('`write` was called after `generate` completed.');
79+
}
80+
// If you see this assert, we're probably being called to build non-canonical
81+
// docs somehow. Check data.self.isCanonical and callers for bugs.
82+
assert(allowOverwrite || !writtenFiles.contains(filePath));
83+
84+
var file = new File(p.join(outputDirectoryPath, filePath));
85+
var parent = file.parent;
86+
if (!parent.existsSync()) {
87+
parent.createSync(recursive: true);
88+
}
89+
90+
if (content is String) {
91+
file.writeAsStringSync(content);
92+
} else if (content is List<int>) {
93+
file.writeAsBytesSync(content);
94+
} else {
95+
throw new ArgumentError.value(
96+
content, 'content', '`content` must be `String` or `List<int>`.');
97+
}
98+
_onFileCreated.add(file);
99+
writtenFiles.add(filePath);
100+
}
101+
102+
try {
103+
_instance =
104+
new HtmlGeneratorInstance(_options, _templates, package, write);
105+
await _instance.generate();
106+
} finally {
107+
enabled = false;
108+
}
74109
}
75110
}
76111

lib/src/html/html_generator_instance.dart

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:async' show Future, StreamController;
5+
import 'dart:async' show Future;
66
import 'dart:convert' show JsonEncoder;
7-
import 'dart:io' show Directory, File;
7+
import 'dart:io' show File;
88

99
import 'package:collection/collection.dart' show compareNatural;
1010
import 'package:dartdoc/src/model_utils.dart';
@@ -19,13 +19,14 @@ import 'resources.g.dart' as resources;
1919
import 'template_data.dart';
2020
import 'templates.dart';
2121

22+
typedef void FileWriter(String path, Object content, {bool allowOverwrite});
23+
2224
class HtmlGeneratorInstance implements HtmlOptions {
2325
final HtmlGeneratorOptions _options;
2426
final Templates _templates;
2527
final Package _package;
26-
final String _outputDirectoryPath;
2728
final List<ModelElement> _documentedElements = <ModelElement>[];
28-
final StreamController<File> _onFileCreated;
29+
final FileWriter _writer;
2930

3031
@override
3132
String get relCanonicalPrefix => _options.relCanonicalPrefix;
@@ -36,12 +37,8 @@ class HtmlGeneratorInstance implements HtmlOptions {
3637
String get _faviconPath => _options.faviconPath;
3738
bool get _useCategories => _options.useCategories;
3839

39-
// Protect against bugs in canonicalization by tracking what files we
40-
// write.
41-
final Set<String> writtenFiles = new Set<String>();
42-
43-
HtmlGeneratorInstance(this._options, this._templates, this._package,
44-
this._outputDirectoryPath, this._onFileCreated);
40+
HtmlGeneratorInstance(
41+
this._options, this._templates, this._package, this._writer);
4542

4643
Future generate() async {
4744
if (_package != null) {
@@ -53,10 +50,8 @@ class HtmlGeneratorInstance implements HtmlOptions {
5350
if (_faviconPath != null) {
5451
var bytes = new File(_faviconPath).readAsBytesSync();
5552
// Allow overwrite of favicon.
56-
String filename =
57-
path.join(_outputDirectoryPath, 'static-assets', 'favicon.png');
58-
writtenFiles.remove(filename);
59-
_writeFile(filename, bytes);
53+
_writer(path.join('static-assets', 'favicon.png'), bytes,
54+
allowOverwrite: true);
6055
}
6156
}
6257

@@ -95,7 +90,7 @@ class HtmlGeneratorInstance implements HtmlOptions {
9590
});
9691

9792
String json = encoder.convert(indexItems);
98-
_writeFile(path.join(_outputDirectoryPath, 'index.json'), '${json}\n');
93+
_writer(path.join('index.json'), '${json}\n');
9994
}
10095

10196
void _generateDocs() {
@@ -285,44 +280,16 @@ class HtmlGeneratorInstance implements HtmlOptions {
285280
'encountered $resourcePath');
286281
}
287282
String destFileName = resourcePath.substring(prefix.length);
288-
_writeFile(path.join(_outputDirectoryPath, 'static-assets', destFileName),
283+
_writer(path.join('static-assets', destFileName),
289284
await loader.loadAsBytes(resourcePath));
290285
}
291286
}
292287

293288
void _build(String filename, TemplateRenderer template, TemplateData data) {
294-
String fullName = path.join(_outputDirectoryPath, filename);
295-
296289
String content = template(data,
297290
assumeNullNonExistingProperty: false, errorOnMissingProperty: true);
298291

299-
_writeFile(fullName, content);
300-
if (data.self is ModelElement) {
301-
_documentedElements.add(data.self);
302-
}
303-
}
304-
305-
/// [content] must be either [String] or [List<int>].
306-
void _writeFile(String filename, Object content) {
307-
// If you see this assert, we're probably being called to build non-canonical
308-
// docs somehow. Check data.self.isCanonical and callers for bugs.
309-
assert(!writtenFiles.contains(filename));
310-
311-
File file = new File(filename);
312-
Directory parent = file.parent;
313-
if (!parent.existsSync()) {
314-
parent.createSync(recursive: true);
315-
}
316-
317-
if (content is String) {
318-
file.writeAsStringSync(content);
319-
} else if (content is List<int>) {
320-
file.writeAsBytesSync(content);
321-
} else {
322-
throw new ArgumentError.value(
323-
content, 'content', '`content` must be `String` or `List<int>`.');
324-
}
325-
_onFileCreated.add(file);
326-
writtenFiles.add(filename);
292+
_writer(filename, content);
293+
if (data.self is ModelElement) _documentedElements.add(data.self);
327294
}
328295
}

0 commit comments

Comments
 (0)