blob: c1e25663939de92cd8ef27631e625cda2898cc2c [file] [log] [blame]
// 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;
import 'package:args/args.dart';
main(args) {
var options = _parseOptions(args);
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();
bool forSite = options['site'];
var out = path.join(path.current, options['out']);
var ext = forSite ? '.markdown' : '.html';
if (!out.endsWith(ext)) {
print('error: expected to have a $ext extension.');
exit(1);
}
sb.write(forSite ? _SITE_HEADER : _LOCAL_HEADER);
var lastPackage = '';
for (var t in templates) {
if (lastPackage != t.id.package) {
lastPackage = t.id.package;
var sectionTitle = '## Messages from package `$lastPackage`\n\n----\n\n';
sb.write(forSite ? sectionTitle : markdownToHtml(sectionTitle));
}
_generateMessage(t, forSite, sb);
}
sb.write(forSite ? '' : _LOCAL_FOOTER);
new File(out).writeAsStringSync(sb.toString());
print('updated: ${options["out"]}');
}
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);
});
}
_generateMessage(MessageTemplate template, bool forSite, StringBuffer sb) {
var details = template.details == null
? 'No details available' : template.details;
if (forSite) details = '{% raw %}$details{% endraw %}';
var id = template.id;
var hashTag = '${id.package}_${id.id}';
var title = '### ${template.description} [#${id.id}](#$hashTag)';
var body = '\n$details\n\n----\n\n';
// We add the anchor inside the <h3> title, otherwise the link doesn't work.
if (forSite) {
sb..write(title)
..write('\n{: #$hashTag}\n')
..write(body);
} else {
var html = markdownToHtml('$title$body').replaceFirst('<hr', '</div><hr');
sb.write('\n\n<div id="$hashTag">$html');
}
}
_parseOptions(args) {
var parser = new ArgParser(allowTrailingOptions: true)
..addOption('out', abbr: 'o',
defaultsTo: 'lib/src/build/generated/messages.html',
help: 'the output file path')
..addFlag('site', abbr: 's', negatable: false,
help: 'generate contents for the dartlang.org site')
..addFlag('help', abbr: 'h', negatable: false);
var options = parser.parse(args);
if (options['help']) {
var command = Platform.script.path;
var relPath = path.relative(command, from: path.current);
if (!relPath.startsWith('../')) command = relPath;
print('usage: dart $command [-o path_to_output_file] [-s]');
print(parser.getUsage());
exit(0);
}
return options;
}
const _SITE_HEADER = '''
---
# WARNING: GENERATED FILE. DO NOT EDIT.
#
# This file was generated automatically from the polymer package.
# To regenerate this file, from the top directory of the polymer package run:
#
# dart tool/create_message_details_page.dart -s -o path_to_this_file
layout: default
title: "Error Messages"
subsite: "Polymer.dart"
description: "Details about error messages from polymer and related packages."
---
{% include breadcrumbs.html %}
# {{ page.title }}
<style>
h3 > a {
display: none;
}
h3:hover > a {
display: inline;
}
</style>
This page contains a list of error messages produced during `pub build` and `pub
serve` by transformers in polymer and its related packages. You can find here
additional details that can often help you figure out how to fix the underlying
problem.
''';
const _LOCAL_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;
background-color: #f0f0f0;
}
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;
}
div:target {
background-color: #fff;
border: 1px solid #888;
border-radius: 5px;
padding: 0px 10px 2px 10px;
box-shadow: 7px 7px 5px #888888;
margin-bottom: 15px;
}
h3 {
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;
}
div:target > h3 {
font-weight: bold;
}
pre {
display: block;
padding: 9.5px;
margin: 0 0 10px;
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;
color: inherit;
background-color: inherit;
}
a {
color: rgb(42, 100, 150);
}
h3 > a {
display: none;
font-size: 0.8em;
}
h3:hover > a {
display: inline;
}
</style>
<body>
''';
const _LOCAL_FOOTER = '''
</body>
</html>
''';