| Index: pkg/polymer/tool/create_message_details_page.dart | 
| diff --git a/pkg/polymer/tool/create_message_details_page.dart b/pkg/polymer/tool/create_message_details_page.dart | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..1724f725fbe38fb0d16a947ca77ba1ab3fe7dc23 | 
| --- /dev/null | 
| +++ b/pkg/polymer/tool/create_message_details_page.dart | 
| @@ -0,0 +1,188 @@ | 
| +// Copyright (c) 2014, 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. | 
| + | 
| +/// Simple script to generate a page summarizing all error messages produces by | 
| +/// the polymer compiler code. The generated code will be placed directly under | 
| +/// the `polymer/lib/src/generated` folder. This script should be invoked from | 
| +/// the root of the polymer package either by doing: | 
| +/// | 
| +///    dart tool/create_message_details_page.dart | 
| +/// | 
| +/// or | 
| +/// | 
| +///    pub run tool/create_message_details_page | 
| +library polymer.tool.create_message_details_page; | 
| + | 
| +import 'dart:io'; | 
| +import 'dart:mirrors'; | 
| + | 
| +import 'package:code_transformers/messages/messages.dart'; | 
| +import 'package:code_transformers/src/messages.dart' as m1; // used via mirrors | 
| +import 'package:observe/src/messages.dart' as m2; // used via mirrors | 
| +import 'package:polymer/src/build/messages.dart' as m3; // used via mirrors | 
| +import 'package:markdown/markdown.dart'; | 
| +import 'package:path/path.dart' as path; | 
| + | 
| +main() { | 
| +  var seen = {}; | 
| +  var templates = []; | 
| +  _getMessagesFrom(#polymer.src.build.messages, seen, templates); | 
| +  _getMessagesFrom(#code_transformers.src.messages, seen, templates); | 
| +  _getMessagesFrom(#observe.src.messages, seen, templates); | 
| + | 
| +  templates.sort((a, b) => a.id.compareTo(b.id)); | 
| +  var sb = new StringBuffer(); | 
| +  sb.write(_HEADER); | 
| + | 
| +  var lastPackage = ''; | 
| +  for (var t in templates) { | 
| +    if (lastPackage != t.id.package) { | 
| +      lastPackage = t.id.package; | 
| +      sb.write(markdownToHtml( | 
| +            '#Messages from package `$lastPackage`\n\n----\n')); | 
| +    } | 
| +    sb.write(_htmlFor(t)); | 
| +  } | 
| +  sb.write(_FOOTER); | 
| +  new File('lib/src/build/generated/messages.html') | 
| +      .writeAsStringSync(sb.toString()); | 
| +} | 
| + | 
| +final _mirrors = currentMirrorSystem(); | 
| + | 
| +_getMessagesFrom(Symbol libName, Map seen, List templates) { | 
| +  var lib = _mirrors.findLibrary(libName); | 
| +  lib.declarations.forEach((symbol, decl) { | 
| +    if (decl is! VariableMirror) return; | 
| +    var template = lib.getField(symbol).reflectee; | 
| +    var name = MirrorSystem.getName(symbol); | 
| +    if (template is! MessageTemplate) return; | 
| +    var id = template.id; | 
| +    if (seen.containsKey(id)) { | 
| +      print('error: duplicate id `$id`. ' | 
| +          'Currently set for both `$name` and `${seen[id]}`.'); | 
| +    } | 
| +    seen[id] = name; | 
| +    templates.add(template); | 
| +  }); | 
| +} | 
| + | 
| +_htmlFor(MessageTemplate template) { | 
| +  var details = template.details == null | 
| +      ? 'No details available' : template.details; | 
| +  var id = template.id; | 
| +  var hashTag = 'msg_${id.package}_${id.id}'; | 
| +  var markdown = | 
| +      '## ${template.description} [#${id.id}](#$hashTag)\n\n$details\n\n----\n'; | 
| +  var html = markdownToHtml(markdown); | 
| +  // We add the anchor inside the <h2> title, otherwise the link doesn't work. | 
| +  return '\n\n${html.replaceFirst("<h2>", "<h2 id=\"$hashTag\">")}'; | 
| +} | 
| + | 
| +const _HEADER = ''' | 
| +<!doctype html> | 
| +<!-- | 
| +  This file is autogenerated with polymer/tool/create_message_details_page.dart | 
| +--> | 
| +<html> | 
| +<style> | 
| +@font-face { | 
| +  font-family: 'Montserrat'; | 
| +  font-style: normal; | 
| +  font-weight: 400; | 
| +  src: url(https://themes.googleusercontent.com/static/fonts/montserrat/v4/zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff) format('woff'); | 
| +} | 
| +@font-face { | 
| +  font-family: 'Montserrat'; | 
| +  font-style: normal; | 
| +  font-weight: 700; | 
| +  src: url(https://themes.googleusercontent.com/static/fonts/montserrat/v4/IQHow_FEYlDC4Gzy_m8fcnbFhgvWbfSbdVg11QabG8w.woff) format('woff'); | 
| +} | 
| +@font-face { | 
| +  font-family: 'Roboto'; | 
| +  font-style: normal; | 
| +  font-weight: 300; | 
| +  src: url(https://themes.googleusercontent.com/static/fonts/roboto/v10/Hgo13k-tfSpn0qi1SFdUfbO3LdcAZYWl9Si6vvxL-qU.woff) format('woff'); | 
| +} | 
| +@font-face { | 
| +  font-family: 'Roboto'; | 
| +  font-style: normal; | 
| +  font-weight: 400; | 
| +  src: url(https://themes.googleusercontent.com/static/fonts/roboto/v10/CrYjSnGjrRCn0pd9VQsnFOvvDin1pK8aKteLpeZ5c0A.woff) format('woff'); | 
| +} | 
| + | 
| +body { | 
| +  width: 80vw; | 
| +  margin: 20px; | 
| +  font-family: Roboto, sans-serif; | 
| +} | 
| + | 
| +h1 { | 
| +  font-family: Montserrat, sans-serif; | 
| +  box-sizing: border-box; | 
| +  color: rgb(72, 72, 72); | 
| +  display: block; | 
| +  font-style: normal; | 
| +  font-variant: normal; | 
| +  font-weight: normal; | 
| +} | 
| + | 
| +h2 { | 
| +  font-family: Montserrat, sans-serif; | 
| +  box-sizing: border-box; | 
| +  color: rgb(72, 72, 72); | 
| +  display: block; | 
| +  font-style: normal; | 
| +  font-variant: normal; | 
| +  font-weight: normal; | 
| +} | 
| + | 
| +pre { | 
| +  display: block; | 
| +  padding: 9.5px; | 
| +  margin: 0 0 10px; | 
| +  line-height: 1.42857143; | 
| +  color: #333; | 
| +  word-break: break-all; | 
| +  word-wrap: break-word; | 
| +  background-color: #f5f5f5; | 
| +  border: 1px solid #ccc; | 
| +  border-radius: 4px; | 
| +} | 
| + | 
| +code { | 
| +   font-family: Menlo,Monaco,Consolas,"Courier New",monospace; | 
| +   box-sizing: border-box; | 
| +   padding: 0; | 
| +   font-size: 90%; | 
| +   color: #0084c5; | 
| +   white-space: nowrap; | 
| +   border-radius: 4px; | 
| +   background-color: #f9f2f4; | 
| +} | 
| + | 
| +pre > code { | 
| +   white-space: inherit; | 
| +} | 
| + | 
| +a { | 
| +  color: rgb(42, 100, 150); | 
| +} | 
| + | 
| +h2 > a { | 
| +  display: none; | 
| +  font-size: 0.8em; | 
| +} | 
| + | 
| +h2:hover > a { | 
| +  display: inline; | 
| +} | 
| +</style> | 
| +<body> | 
| +'''; | 
| + | 
| +const _FOOTER = ''' | 
| +</body> | 
| +</html> | 
| +'''; | 
|  |