Index: pkg/dart_messages/bin/publish.dart |
diff --git a/pkg/dart_messages/bin/publish.dart b/pkg/dart_messages/bin/publish.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..426e3baed7701e0940864ac48dd845a60c43aba7 |
--- /dev/null |
+++ b/pkg/dart_messages/bin/publish.dart |
@@ -0,0 +1,224 @@ |
+// Copyright (c) 2015, 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. |
+ |
+import 'dart:convert'; |
+import 'dart:io'; |
+ |
+import '../lib/shared_messages.dart'; |
+ |
+const String jsonPath = '../lib/generated/shared_messages.json'; |
+const String dart2jsPath = |
+ '../../compiler/lib/src/diagnostics/generated/shared_messages.dart'; |
+const String analyzerPath = |
+ '../../analyzer/lib/src/generated/generated/shared_messages.dart'; |
+ |
+final String dontEditWarning = """ |
+/* |
+DON'T EDIT. GENERATED. DON'T EDIT. |
+This file has been generated by 'publish.dart' in the dart_messages package. |
+ |
+Messages are maintained in `lib/shared_messages.dart` of that same package. |
+After any change to that file, run `bin/publish.dart` to generate a new version |
+of the json, dart2js and analyzer representations. |
+*/"""; |
+ |
+const String copyrightHeader = ''' |
+// Copyright (c) 2015, 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.'''; |
+ |
+void markAsReadonly(String path) { |
+ // TODO(15078): mark as read-only. Currently not possible: |
+ // http://dartbug.com/15078. |
+} |
+ |
+void emitJson() { |
+ var input = MESSAGES; |
+ var outPath = Platform.script.resolve(jsonPath).toFilePath(); |
+ print("Emitting JSON:"); |
+ print(" Input: ${input.length} entries"); |
+ print(" Output: $outPath"); |
+ new File(outPath).writeAsStringSync(messagesAsJson); |
+ print("Emitting JSON done."); |
+} |
+ |
+/// Escapes the given string [str]. |
+/// |
+/// The parameter [str] may be `null` in which case the result is "null". |
+String escapeString(String str) { |
+ return JSON.encode(str); |
+} |
+ |
+/// Emits the messages in dart2js format. |
+/// |
+/// The dart2js-format consists of two entities: |
+/// 1. the `MessageKind` enum, and |
+/// 2. the MessageKind-to-Template map `TEMPLATES`. |
+/// |
+/// The template is an instance of MessageTemplate: |
+/// |
+/// const MessageTemplate( |
+/// this.kind, |
+/// this.template, |
+/// {this.howToFix, |
+/// this.examples, |
+/// this.options: const <String>[]}); |
+/// |
+/// A sample output thus looks as follows: |
+/// |
+/// enum MessageKind { |
+/// EXAMPLE_MESSAGE, |
+/// } |
+/// |
+/// const Map<MessageKind, MessageTemplate> { |
+/// EXAMPLE_MESSAGE: const MessageTemplate( |
+/// EXAMPLE_MESSAGE, |
+/// "Don't use #foo with #bar", |
+/// howToFix: "Just don't do it", |
+/// options: const ['--some-flag']), |
+/// examples: const [''' |
+/// some example with bad code;'''], |
+/// }; |
+void emitDart2js() { |
+ var input = MESSAGES; |
+ var outPath = Platform.script.resolve(dart2jsPath).toFilePath(); |
+ print("Emitting dart2js:"); |
+ print(" Input: ${input.length} entries"); |
+ print(" Output: $outPath"); |
+ |
+ var enumIds = input.keys.toList(); |
+ |
+ StringBuffer out = new StringBuffer(); |
+ out.writeln(dontEditWarning); |
+ out.writeln(copyrightHeader); |
+ out.writeln("import '../messages.dart' show MessageTemplate;"); |
+ out.writeln(); |
+ out.write(("enum SharedMessageKind {\n ")); |
+ // We generate on one line on purpose, so that users are less likely to |
+ // modify the generated file. |
+ out.writeln(enumIds.join(",\n ")); |
+ out.writeln("}"); |
+ out.writeln(); |
+ out.writeln("const Map<SharedMessageKind, MessageTemplate> TEMPLATES = " |
+ "const <SharedMessageKind, MessageTemplate>{ "); |
+ input.forEach((name, message) { |
+ out.writeln(" SharedMessageKind.$name: const MessageTemplate("); |
+ // TODO(floitsch): include id. |
+ out.writeln(" SharedMessageKind.$name,"); |
+ out.write(" "); |
+ out.write(escapeString(message.template)); |
+ if (message.howToFix != null) { |
+ out.write(",\n howToFix: ${escapeString(message.howToFix)}"); |
+ } |
+ if (message.options != null) { |
+ out.write(",\n options: const ["); |
+ out.write(message.options.map(escapeString).join(",")); |
+ out.writeln("]"); |
+ } |
+ if (message.examples != null) { |
+ out.writeln(",\n examples: const ["); |
+ for (var example in message.examples) { |
+ if (example is String) { |
+ out.writeln(" r'''"); |
+ out.write(example); |
+ out.write("'''"); |
+ } else if (example is Map) { |
+ out.writeln(" const {"); |
+ example.forEach((String fileName, String content) { |
+ out.writeln(" '$fileName': r'''"); |
+ out.write(content); |
+ out.writeln("''',"); |
+ }); |
+ out.write(" }"); |
+ } |
+ out.writeln(","); |
+ } |
+ out.writeln(" ]"); |
+ } |
+ out.writeln(" ), // Generated. Don't edit."); |
+ }); |
+ out.writeln("};"); |
+ |
+ new File(outPath).writeAsStringSync(out.toString()); |
+ print("Emitting dart2js done."); |
+} |
+ |
+String convertToAnalyzerTemplate(String template, holeOrder) { |
+ var holeMap; |
+ if (holeOrder != null) { |
+ holeMap = {}; |
+ for (int i = 0; i < holeOrder.length; i++) { |
+ holeMap[holeOrder[i]] = i; |
+ } |
+ } |
+ int seenHoles = 0; |
+ return template.replaceAllMapped(new RegExp(r"#\w+"), (Match match) { |
+ if (holeMap != null) { |
+ String holeName = match[0].substring(1); |
+ int index = holeMap[holeName]; |
+ if (index == null) { |
+ throw "Couldn't find hole-position for $holeName $holeMap"; |
+ } |
+ return "{$index}"; |
+ } else { |
+ return "{${seenHoles++}}"; |
+ } |
+ }); |
+} |
+ |
+/// Emits the messages in analyzer format. |
+/// |
+/// Messages are encoded as instances of `ErrorCode` classes where the |
+/// corresponding class is given by the `category` field of the Message. |
+/// |
+/// All instances are stored as top-level const variables. |
+/// |
+/// A sample output looks as follows: |
+/// |
+/// const FooCategoryErrorCode EXAMPLE_MESSAGE = const FooCategoryErrorCode( |
+/// "EXAMPLE_MESSAGE", |
+/// "Don't use {0} with {1}", |
+/// "Just don't do it"); |
+void emitAnalyzer() { |
+ var input = MESSAGES; |
+ var outPath = Platform.script.resolve(analyzerPath).toFilePath(); |
+ print("Emitting analyzer:"); |
+ print(" Input: ${input.length} entries"); |
+ print(" Output: $outPath"); |
+ |
+ StringBuffer out = new StringBuffer(); |
+ out.writeln(dontEditWarning); |
+ out.writeln(copyrightHeader); |
+ out.writeln("import 'package:analyzer/src/generated/error.dart';"); |
+ out.writeln(); |
+ input.forEach((name, message) { |
+ Category category = message.category; |
+ String className = category.name + "Code"; |
+ out.writeln("const $className $name = const $className("); |
+ out.writeln(" '$name',"); |
+ |
+ String template = message.template; |
+ List holeOrder = message.templateHoleOrder; |
+ String analyzerTemplate = convertToAnalyzerTemplate(template, holeOrder); |
+ out.write(" "); |
+ out.write(escapeString(analyzerTemplate)); |
+ out.write(",\n "); |
+ out.write(escapeString(message.howToFix)); |
+ out.writeln("); // Generated. Don't edit."); |
+ }); |
+ |
+ new File(outPath).writeAsStringSync(out.toString()); |
+ print("Emitting analyzer done."); |
+} |
+ |
+/// Translates the shared messages in `../lib/shared_messages.dart` to JSON, |
+/// dart2js, and analyzer formats. |
+/// |
+/// Emits the json-output to [jsonPath], the dart2js-output to [dart2jsPath], |
+/// and the analyzer-output to [analyzerPath]. |
+void main() { |
+ emitJson(); |
+ emitDart2js(); |
+ emitAnalyzer(); |
+} |