blob: 1b561117ae12ce4266cdceb56fa8a2245fa04036 [file] [log] [blame]
// Copyright (c) 2012, 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.
/**
* Library for taking a JSON file and putting the comments located within into
* the HTML files the comments are associated with.
*
* The format of the JSON file is:
*
* {
* "$filename":
* {
* "$lineInHtml":
* [
* "lines of comment",
* "here"
* ]
* },
* ...
* }
*/
library json_to_html;
import 'dart:json' as JSON;
import 'dart:io';
import 'dart:async';
/// True if any errors were triggered through the conversion.
bool _anyErrors = false;
/**
* Take comments from [jsonPath] and apply them to all the files found in
* [htmlPath]. This will overwrite the files in htmlPath.
*/
Future<bool> convert(Path htmlPath, Path jsonPath) {
final completer = new Completer();
final jsonFile = new File.fromPath(jsonPath);
final htmlDir = new Directory.fromPath(htmlPath);
if (!jsonFile.existsSync()) {
print("ERROR: No JSON file found at: ${jsonPath}");
_anyErrors = true;
completer.complete(false);
} else if (!htmlDir.existsSync()) {
print("ERROR: No HTML directory found at: ${htmlPath}");
_anyErrors = true;
completer.complete(false);
}
var fileJson = {};
var jsonRead = jsonFile.readAsStringSync();
if (jsonRead == '') {
print('WARNING: no data read from ${jsonPath.filename}');
_anyErrors = true;
completer.complete(false);
} else {
fileJson = JSON.parse(jsonRead);
}
// TODO(amouravski): Refactor to not duplicate code here and in html-to-json.
// Find html files. (lister)
final lister = htmlDir.list(recursive: false);
lister.onFile = (String path) {
final name = new Path(path).filename;
// Ignore private classes.
if (name.startsWith('_')) return;
// Ignore non-dart files.
if (!name.endsWith('.dart')) return;
File file = new File(path);
// TODO(amouravski): Handle missing file.
if (!file.existsSync()) {
print('ERROR: cannot find file: $path');
_anyErrors = true;
return;
}
if (!fileJson.containsKey(name)) {
print('WARNING: file found that is not in JSON: $path');
_anyErrors = true;
return;
}
var comments = fileJson[name];
_convertFile(file, comments);
fileJson.remove(name);
};
lister.onDone = (_) {
fileJson.forEach((key, _) {
print('WARNING: the following filename was found in the JSON but not in '
'${htmlDir.path}:\n"$key"');
_anyErrors = true;
});
completer.complete(_anyErrors);
};
return completer.future;
}
/**
* Inserts the comments from JSON into a single file.
*/
void _convertFile(File file, Map<String, List<String>> comments) {
var fileLines = file.readAsLinesSync();
var unusedComments = {};
comments.forEach((key, comments) {
var index = fileLines.indexOf(key);
// If the key is found in any line past the first one.
if (index > 0 && fileLines[index - 1].trim().startsWith('///') &&
fileLines[index - 1].contains('@docsEditable')) {
// Add comments.
fileLines.insertRange(index - 1, comments.length);
fileLines.setRange(index - 1, comments.length, comments);
} else {
unusedComments.putIfAbsent(key, () => comments);
}
});
unusedComments.forEach((String key, _) {
print('WARNING: the following key was found in the JSON but not in '
'${new Path(file.fullPathSync()).filename}:\n"$key"');
_anyErrors = true;
});
for (var i = 0; i < fileLines.length; ++i) {
fileLines[i] = fileLines[i].replaceAll(new RegExp(r'\s+$'), '');
}
// TODO(amouravski): file.writeAsStringSync('${Strings.join(fileLines, '\n')}\n');
var outputStream = file.openOutputStream();
outputStream.writeString(Strings.join(fileLines, '\n'));
outputStream.writeString('\n');
outputStream.onNoPendingWrites = () {
outputStream.close();
};
}