Index: pkg/analysis_server/tool/spec/codegen_tools.dart |
diff --git a/pkg/analysis_server/tool/spec/codegen_tools.dart b/pkg/analysis_server/tool/spec/codegen_tools.dart |
index f97c8bb868b585870bafc523c9a90430916b6827..922b4823de6eb4a804bf55dff70313027f8a3209 100644 |
--- a/pkg/analysis_server/tool/spec/codegen_tools.dart |
+++ b/pkg/analysis_server/tool/spec/codegen_tools.dart |
@@ -12,8 +12,10 @@ import 'dart:io'; |
import 'package:html5lib/dom.dart' as dom; |
import 'package:path/path.dart'; |
-import 'text_formatter.dart'; |
import 'html_tools.dart'; |
+import 'text_formatter.dart'; |
+ |
+final RegExp trailingWhitespaceRegExp = new RegExp(r' +$', multiLine: true); |
/** |
* Join the given strings using camelCase. If [doCapitalize] is true, the first |
@@ -38,7 +40,15 @@ String capitalize(String string) { |
return string[0].toUpperCase() + string.substring(1); |
} |
-final RegExp trailingWhitespaceRegExp = new RegExp(r' +$', multiLine: true); |
+/** |
+ * Type of functions used to compute the contents of a set of generated files. |
+ */ |
+typedef Map<String, FileContentsComputer> DirectoryContentsComputer(); |
+ |
+/** |
+ * Type of functions used to compute the contents of a generated file. |
+ */ |
+typedef String FileContentsComputer(); |
/** |
* Mixin class for generating code. |
@@ -47,6 +57,11 @@ class CodeGenerator { |
_CodeGeneratorState _state; |
/** |
+ * Measure the width of the current indentation level. |
+ */ |
+ int get indentWidth => _state.nextIndent.length; |
+ |
+ /** |
* Execute [callback], collecting any code that is output using [write] |
* or [writeln], and return the result as a string. |
*/ |
@@ -62,17 +77,21 @@ class CodeGenerator { |
} |
/** |
- * Output text without ending the current line. |
- */ |
- void write(Object obj) { |
- _state.write(obj.toString()); |
- } |
- |
- /** |
- * Output text, ending the current line. |
+ * Generate a doc comment based on the HTML in [docs]. |
+ * |
+ * If [javadocStyle] is true, then the output is compatable with Javadoc, |
+ * which understands certain HTML constructs. |
*/ |
- void writeln([Object obj = '']) { |
- _state.write('$obj\n'); |
+ void docComment(List<dom.Node> docs, {int width: 79, bool javadocStyle: |
+ false}) { |
+ if (containsOnlyWhitespace(docs)) { |
+ return; |
+ } |
+ writeln('/**'); |
+ indentBy(' * ', () { |
+ write(nodesToText(docs, width - _state.indent.length, javadocStyle)); |
+ }); |
+ writeln(' */'); |
} |
/** |
@@ -105,29 +124,6 @@ class CodeGenerator { |
} |
} |
- /** |
- * Measure the width of the current indentation level. |
- */ |
- int get indentWidth => _state.nextIndent.length; |
- |
- /** |
- * Generate a doc comment based on the HTML in [docs]. |
- * |
- * If [javadocStyle] is true, then the output is compatable with Javadoc, |
- * which understands certain HTML constructs. |
- */ |
- void docComment(List<dom.Node> docs, {int width: 79, bool javadocStyle: |
- false}) { |
- if (containsOnlyWhitespace(docs)) { |
- return; |
- } |
- writeln('/**'); |
- indentBy(' * ', () { |
- write(nodesToText(docs, width - _state.indent.length, javadocStyle)); |
- }); |
- writeln(' */'); |
- } |
- |
void outputHeader({bool javaStyle: false}) { |
String header; |
if (javaStyle) { |
@@ -161,166 +157,118 @@ class CodeGenerator { |
} |
writeln(header.trim()); |
} |
-} |
- |
-/** |
- * State used by [CodeGenerator]. |
- */ |
-class _CodeGeneratorState { |
- StringBuffer buffer = new StringBuffer(); |
- String nextIndent = ''; |
- String indent = ''; |
- bool indentNeeded = true; |
- |
- void write(String text) { |
- List<String> lines = text.split('\n'); |
- for (int i = 0; i < lines.length; i++) { |
- if (i == lines.length - 1 && lines[i].isEmpty) { |
- break; |
- } |
- if (indentNeeded) { |
- buffer.write(nextIndent); |
- nextIndent = indent; |
- } |
- indentNeeded = false; |
- buffer.write(lines[i]); |
- if (i != lines.length - 1) { |
- buffer.writeln(); |
- indentNeeded = true; |
- } |
- } |
- } |
-} |
- |
-/** |
- * Mixin class for generating HTML representations of code that are suitable |
- * for enclosing inside a <pre> element. |
- */ |
-abstract class HtmlCodeGenerator { |
- _HtmlCodeGeneratorState _state; |
/** |
- * Execute [callback], collecting any code that is output using [write], |
- * [writeln], [add], or [addAll], and return the result as a list of DOM |
- * nodes. |
+ * Output text without ending the current line. |
*/ |
- List<dom.Node> collectHtml(void callback()) { |
- _HtmlCodeGeneratorState oldState = _state; |
- try { |
- _state = new _HtmlCodeGeneratorState(); |
- if (callback != null) { |
- callback(); |
- } |
- return _state.buffer; |
- } finally { |
- _state = oldState; |
- } |
+ void write(Object obj) { |
+ _state.write(obj.toString()); |
} |
/** |
- * Add the given [node] to the HTML output. |
+ * Output text, ending the current line. |
*/ |
- void add(dom.Node node) { |
- _state.add(node); |
+ void writeln([Object obj = '']) { |
+ _state.write('$obj\n'); |
} |
+} |
+ |
+abstract class GeneratedContent { |
+ FileSystemEntity get outputFile; |
+ bool check(); |
+ void generate(); |
+} |
+ |
+/** |
+ * Class representing a single output directory (either generated code or |
+ * generated HTML). No other content should exisit in the directory. |
+ */ |
+class GeneratedDirectory extends GeneratedContent { |
/** |
- * Add the given [nodes] to the HTML output. |
+ * The path to the directory that will have the generated content. |
*/ |
- void addAll(Iterable<dom.Node> nodes) { |
- for (dom.Node node in nodes) { |
- _state.add(node); |
- } |
- } |
+ final String outputDirPath; |
/** |
- * Output text without ending the current line. |
+ * Callback function which computes the directory contents. |
*/ |
- void write(Object obj) { |
- _state.write(obj.toString()); |
- } |
+ final DirectoryContentsComputer directoryContentsComputer; |
+ |
+ GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); |
/** |
- * Output text, ending the current line. |
+ * Get a Directory object representing the output directory. |
*/ |
- void writeln([Object obj = '']) { |
- _state.write('$obj\n'); |
- } |
+ Directory get outputFile => |
+ new Directory(joinAll(posix.split(outputDirPath))); |
/** |
- * Execute [callback], indenting any code it outputs by two spaces. |
+ * Check whether the directory has the correct contents, and return true if it |
+ * does. |
*/ |
- void indent(void callback()) { |
- String oldIndent = _state.indent; |
+ @override |
+ bool check() { |
+ Map<String, FileContentsComputer> map = directoryContentsComputer(); |
try { |
- _state.indent += ' '; |
- callback(); |
- } finally { |
- _state.indent = oldIndent; |
+ map.forEach((String file, FileContentsComputer fileContentsComputer) { |
+ String expectedContents = fileContentsComputer(); |
+ File outputFile = |
+ new File(joinAll(posix.split(posix.join(outputDirPath, file)))); |
+ if (expectedContents != outputFile.readAsStringSync()) { |
+ return false; |
+ } |
+ }); |
+ int nonHiddenFileCount = 0; |
+ outputFile.listSync( |
+ recursive: false, |
+ followLinks: false).forEach((FileSystemEntity fileSystemEntity) { |
+ if (fileSystemEntity is File && |
+ !basename(fileSystemEntity.path).startsWith('.')) { |
+ nonHiddenFileCount++; |
+ } |
+ }); |
+ if (nonHiddenFileCount != map.length) { |
+ // The number of files generated doesn't match the number we expected to |
+ // generate. |
+ return false; |
+ } |
+ } catch (e) { |
+ // There was a problem reading the file (most likely because it didn't |
+ // exist). Treat that the same as if the file doesn't have the expected |
+ // contents. |
+ return false; |
} |
+ return true; |
} |
/** |
- * Execute [callback], wrapping its output in an element with the given |
- * [name] and [attributes]. |
+ * Replace the directory with the correct contents. [spec] is the "tool/spec" |
+ * directory. If [spec] is unspecified, it is assumed to be the directory |
+ * containing Platform.executable. |
*/ |
- void element(String name, Map<String, String> attributes, [void callback()]) { |
- add(makeElement(name, attributes, collectHtml(callback))); |
- } |
-} |
- |
-/** |
- * State used by [HtmlCodeGenerator]. |
- */ |
-class _HtmlCodeGeneratorState { |
- List<dom.Node> buffer = <dom.Node>[]; |
- String indent = ''; |
- bool indentNeeded = true; |
- |
- void add(dom.Node node) { |
- if (node is dom.Text) { |
- write(node.text); |
- } else { |
- buffer.add(node); |
+ @override |
+ void generate() { |
+ try { |
+ // delete the contents of the directory (and the directory itself) |
+ outputFile.deleteSync(recursive: true); |
+ } catch (e) { |
+ // Error caught while trying to delete the directory, this can happen if |
+ // it didn't yet exist. |
} |
- } |
+ // re-create the empty directory |
+ outputFile.createSync(recursive: true); |
- void write(String text) { |
- if (text.isEmpty) { |
- return; |
- } |
- if (indentNeeded) { |
- buffer.add(new dom.Text(indent)); |
- } |
- List<String> lines = text.split('\n'); |
- if (lines.last.isEmpty) { |
- lines.removeLast(); |
- buffer.add(new dom.Text(lines.join('\n$indent') + '\n')); |
- indentNeeded = true; |
- } else { |
- buffer.add(new dom.Text(lines.join('\n$indent'))); |
- indentNeeded = false; |
- } |
+ // generate all of the files in the directory |
+ Map<String, FileContentsComputer> map = directoryContentsComputer(); |
+ map.forEach((String file, FileContentsComputer fileContentsComputer) { |
+ File outputFile = new File(joinAll(posix.split(outputDirPath + file))); |
+ outputFile.writeAsStringSync(fileContentsComputer()); |
+ }); |
} |
} |
/** |
- * Type of functions used to compute the contents of a generated file. |
- */ |
-typedef String FileContentsComputer(); |
- |
-/** |
- * Type of functions used to compute the contents of a set of generated files. |
- */ |
-typedef Map<String, FileContentsComputer> DirectoryContentsComputer(); |
- |
-abstract class GeneratedContent { |
- FileSystemEntity get outputFile; |
- bool check(); |
- void generate(); |
-} |
- |
-/** |
* Class representing a single output file (either generated code or generated |
* HTML). |
*/ |
@@ -372,89 +320,142 @@ class GeneratedFile extends GeneratedContent { |
} |
/** |
- * Class representing a single output directory (either generated code or |
- * generated HTML). No other content should exisit in the directory. |
+ * Mixin class for generating HTML representations of code that are suitable |
+ * for enclosing inside a <pre> element. |
*/ |
-class GeneratedDirectory extends GeneratedContent { |
+abstract class HtmlCodeGenerator { |
+ _HtmlCodeGeneratorState _state; |
/** |
- * The path to the directory that will have the generated content. |
+ * Add the given [node] to the HTML output. |
*/ |
- final String outputDirPath; |
+ void add(dom.Node node) { |
+ _state.add(node); |
+ } |
/** |
- * Callback function which computes the directory contents. |
+ * Add the given [nodes] to the HTML output. |
*/ |
- final DirectoryContentsComputer directoryContentsComputer; |
+ void addAll(Iterable<dom.Node> nodes) { |
+ for (dom.Node node in nodes) { |
+ _state.add(node); |
+ } |
+ } |
- GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); |
+ /** |
+ * Execute [callback], collecting any code that is output using [write], |
+ * [writeln], [add], or [addAll], and return the result as a list of DOM |
+ * nodes. |
+ */ |
+ List<dom.Node> collectHtml(void callback()) { |
+ _HtmlCodeGeneratorState oldState = _state; |
+ try { |
+ _state = new _HtmlCodeGeneratorState(); |
+ if (callback != null) { |
+ callback(); |
+ } |
+ return _state.buffer; |
+ } finally { |
+ _state = oldState; |
+ } |
+ } |
/** |
- * Get a Directory object representing the output directory. |
+ * Execute [callback], wrapping its output in an element with the given |
+ * [name] and [attributes]. |
*/ |
- Directory get outputFile => |
- new Directory(joinAll(posix.split(outputDirPath))); |
+ void element(String name, Map<String, String> attributes, [void callback()]) { |
+ add(makeElement(name, attributes, collectHtml(callback))); |
+ } |
/** |
- * Check whether the directory has the correct contents, and return true if it |
- * does. |
+ * Execute [callback], indenting any code it outputs by two spaces. |
*/ |
- @override |
- bool check() { |
- Map<String, FileContentsComputer> map = directoryContentsComputer(); |
+ void indent(void callback()) { |
+ String oldIndent = _state.indent; |
try { |
- map.forEach((String file, FileContentsComputer fileContentsComputer) { |
- String expectedContents = fileContentsComputer(); |
- File outputFile = |
- new File(joinAll(posix.split(posix.join(outputDirPath, file)))); |
- if (expectedContents != outputFile.readAsStringSync()) { |
- return false; |
- } |
- }); |
- int nonHiddenFileCount = 0; |
- outputFile.listSync( |
- recursive: false, |
- followLinks: false).forEach((FileSystemEntity fileSystemEntity) { |
- if(fileSystemEntity is File && !basename(fileSystemEntity.path).startsWith('.')) { |
- nonHiddenFileCount++; |
- } |
- }); |
- if (nonHiddenFileCount != map.length) { |
- // The number of files generated doesn't match the number we expected to |
- // generate. |
- return false; |
- } |
- } catch (e) { |
- // There was a problem reading the file (most likely because it didn't |
- // exist). Treat that the same as if the file doesn't have the expected |
- // contents. |
- return false; |
+ _state.indent += ' '; |
+ callback(); |
+ } finally { |
+ _state.indent = oldIndent; |
} |
- return true; |
} |
/** |
- * Replace the directory with the correct contents. [spec] is the "tool/spec" |
- * directory. If [spec] is unspecified, it is assumed to be the directory |
- * containing Platform.executable. |
+ * Output text without ending the current line. |
*/ |
- @override |
- void generate() { |
- try { |
- // delete the contents of the directory (and the directory itself) |
- outputFile.deleteSync(recursive: true); |
- } catch (e) { |
- // Error caught while trying to delete the directory, this can happen if |
- // it didn't yet exist. |
+ void write(Object obj) { |
+ _state.write(obj.toString()); |
+ } |
+ |
+ /** |
+ * Output text, ending the current line. |
+ */ |
+ void writeln([Object obj = '']) { |
+ _state.write('$obj\n'); |
+ } |
+} |
+ |
+/** |
+ * State used by [CodeGenerator]. |
+ */ |
+class _CodeGeneratorState { |
+ StringBuffer buffer = new StringBuffer(); |
+ String nextIndent = ''; |
+ String indent = ''; |
+ bool indentNeeded = true; |
+ |
+ void write(String text) { |
+ List<String> lines = text.split('\n'); |
+ for (int i = 0; i < lines.length; i++) { |
+ if (i == lines.length - 1 && lines[i].isEmpty) { |
+ break; |
+ } |
+ if (indentNeeded) { |
+ buffer.write(nextIndent); |
+ nextIndent = indent; |
+ } |
+ indentNeeded = false; |
+ buffer.write(lines[i]); |
+ if (i != lines.length - 1) { |
+ buffer.writeln(); |
+ indentNeeded = true; |
+ } |
} |
- // re-create the empty directory |
- outputFile.createSync(recursive: true); |
+ } |
+} |
- // generate all of the files in the directory |
- Map<String, FileContentsComputer> map = directoryContentsComputer(); |
- map.forEach((String file, FileContentsComputer fileContentsComputer) { |
- File outputFile = new File(joinAll(posix.split(outputDirPath + file))); |
- outputFile.writeAsStringSync(fileContentsComputer()); |
- }); |
+/** |
+ * State used by [HtmlCodeGenerator]. |
+ */ |
+class _HtmlCodeGeneratorState { |
+ List<dom.Node> buffer = <dom.Node>[]; |
+ String indent = ''; |
+ bool indentNeeded = true; |
+ |
+ void add(dom.Node node) { |
+ if (node is dom.Text) { |
+ write(node.text); |
+ } else { |
+ buffer.add(node); |
+ } |
+ } |
+ |
+ void write(String text) { |
+ if (text.isEmpty) { |
+ return; |
+ } |
+ if (indentNeeded) { |
+ buffer.add(new dom.Text(indent)); |
+ } |
+ List<String> lines = text.split('\n'); |
+ if (lines.last.isEmpty) { |
+ lines.removeLast(); |
+ buffer.add(new dom.Text(lines.join('\n$indent') + '\n')); |
+ indentNeeded = true; |
+ } else { |
+ buffer.add(new dom.Text(lines.join('\n$indent'))); |
+ indentNeeded = false; |
+ } |
} |
} |