OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'dart:convert'; |
| 6 import 'dart:io'; |
| 7 |
| 8 import '../lib/shared_messages.dart'; |
| 9 |
| 10 const String jsonPath = '../lib/generated/shared_messages.json'; |
| 11 const String dart2jsPath = |
| 12 '../../compiler/lib/src/diagnostics/generated/shared_messages.dart'; |
| 13 const String analyzerPath = |
| 14 '../../analyzer/lib/src/generated/generated/shared_messages.dart'; |
| 15 |
| 16 final String dontEditWarning = """ |
| 17 /* |
| 18 DON'T EDIT. GENERATED. DON'T EDIT. |
| 19 This file has been generated by 'publish.dart' in the dart_messages package. |
| 20 |
| 21 Messages are maintained in `lib/shared_messages.dart` of that same package. |
| 22 After any change to that file, run `bin/publish.dart` to generate a new version |
| 23 of the json, dart2js and analyzer representations. |
| 24 */"""; |
| 25 |
| 26 const String copyrightHeader = ''' |
| 27 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 28 // for details. All rights reserved. Use of this source code is governed by a |
| 29 // BSD-style license that can be found in the LICENSE file.'''; |
| 30 |
| 31 void markAsReadonly(String path) { |
| 32 // TODO(15078): mark as read-only. Currently not possible: |
| 33 // http://dartbug.com/15078. |
| 34 } |
| 35 |
| 36 void emitJson() { |
| 37 var input = MESSAGES; |
| 38 var outPath = Platform.script.resolve(jsonPath).toFilePath(); |
| 39 print("Emitting JSON:"); |
| 40 print(" Input: ${input.length} entries"); |
| 41 print(" Output: $outPath"); |
| 42 new File(outPath).writeAsStringSync(messagesAsJson); |
| 43 print("Emitting JSON done."); |
| 44 } |
| 45 |
| 46 /// Escapes the given string [str]. |
| 47 /// |
| 48 /// The parameter [str] may be `null` in which case the result is "null". |
| 49 String escapeString(String str) { |
| 50 return JSON.encode(str); |
| 51 } |
| 52 |
| 53 /// Emits the messages in dart2js format. |
| 54 /// |
| 55 /// The dart2js-format consists of two entities: |
| 56 /// 1. the `MessageKind` enum, and |
| 57 /// 2. the MessageKind-to-Template map `TEMPLATES`. |
| 58 /// |
| 59 /// The template is an instance of MessageTemplate: |
| 60 /// |
| 61 /// const MessageTemplate( |
| 62 /// this.kind, |
| 63 /// this.template, |
| 64 /// {this.howToFix, |
| 65 /// this.examples, |
| 66 /// this.options: const <String>[]}); |
| 67 /// |
| 68 /// A sample output thus looks as follows: |
| 69 /// |
| 70 /// enum MessageKind { |
| 71 /// EXAMPLE_MESSAGE, |
| 72 /// } |
| 73 /// |
| 74 /// const Map<MessageKind, MessageTemplate> { |
| 75 /// EXAMPLE_MESSAGE: const MessageTemplate( |
| 76 /// EXAMPLE_MESSAGE, |
| 77 /// "Don't use #foo with #bar", |
| 78 /// howToFix: "Just don't do it", |
| 79 /// options: const ['--some-flag']), |
| 80 /// examples: const [''' |
| 81 /// some example with bad code;'''], |
| 82 /// }; |
| 83 void emitDart2js() { |
| 84 var input = MESSAGES; |
| 85 var outPath = Platform.script.resolve(dart2jsPath).toFilePath(); |
| 86 print("Emitting dart2js:"); |
| 87 print(" Input: ${input.length} entries"); |
| 88 print(" Output: $outPath"); |
| 89 |
| 90 var enumIds = input.keys.toList(); |
| 91 |
| 92 StringBuffer out = new StringBuffer(); |
| 93 out.writeln(dontEditWarning); |
| 94 out.writeln(copyrightHeader); |
| 95 out.writeln("import '../messages.dart' show MessageTemplate;"); |
| 96 out.writeln(); |
| 97 out.write(("enum SharedMessageKind {\n ")); |
| 98 // We generate on one line on purpose, so that users are less likely to |
| 99 // modify the generated file. |
| 100 out.writeln(enumIds.join(",\n ")); |
| 101 out.writeln("}"); |
| 102 out.writeln(); |
| 103 out.writeln("const Map<SharedMessageKind, MessageTemplate> TEMPLATES = " |
| 104 "const <SharedMessageKind, MessageTemplate>{ "); |
| 105 input.forEach((name, message) { |
| 106 out.writeln(" SharedMessageKind.$name: const MessageTemplate("); |
| 107 // TODO(floitsch): include id. |
| 108 out.writeln(" SharedMessageKind.$name,"); |
| 109 out.write(" "); |
| 110 out.write(escapeString(message.template)); |
| 111 if (message.howToFix != null) { |
| 112 out.write(",\n howToFix: ${escapeString(message.howToFix)}"); |
| 113 } |
| 114 if (message.options != null) { |
| 115 out.write(",\n options: const ["); |
| 116 out.write(message.options.map(escapeString).join(",")); |
| 117 out.writeln("]"); |
| 118 } |
| 119 if (message.examples != null) { |
| 120 out.writeln(",\n examples: const ["); |
| 121 for (var example in message.examples) { |
| 122 if (example is String) { |
| 123 out.writeln(" r'''"); |
| 124 out.write(example); |
| 125 out.write("'''"); |
| 126 } else if (example is Map) { |
| 127 out.writeln(" const {"); |
| 128 example.forEach((String fileName, String content) { |
| 129 out.writeln(" '$fileName': r'''"); |
| 130 out.write(content); |
| 131 out.writeln("''',"); |
| 132 }); |
| 133 out.write(" }"); |
| 134 } |
| 135 out.writeln(","); |
| 136 } |
| 137 out.writeln(" ]"); |
| 138 } |
| 139 out.writeln(" ), // Generated. Don't edit."); |
| 140 }); |
| 141 out.writeln("};"); |
| 142 |
| 143 new File(outPath).writeAsStringSync(out.toString()); |
| 144 print("Emitting dart2js done."); |
| 145 } |
| 146 |
| 147 String convertToAnalyzerTemplate(String template, holeOrder) { |
| 148 var holeMap; |
| 149 if (holeOrder != null) { |
| 150 holeMap = {}; |
| 151 for (int i = 0; i < holeOrder.length; i++) { |
| 152 holeMap[holeOrder[i]] = i; |
| 153 } |
| 154 } |
| 155 int seenHoles = 0; |
| 156 return template.replaceAllMapped(new RegExp(r"#\w+"), (Match match) { |
| 157 if (holeMap != null) { |
| 158 String holeName = match[0].substring(1); |
| 159 int index = holeMap[holeName]; |
| 160 if (index == null) { |
| 161 throw "Couldn't find hole-position for $holeName $holeMap"; |
| 162 } |
| 163 return "{$index}"; |
| 164 } else { |
| 165 return "{${seenHoles++}}"; |
| 166 } |
| 167 }); |
| 168 } |
| 169 |
| 170 /// Emits the messages in analyzer format. |
| 171 /// |
| 172 /// Messages are encoded as instances of `ErrorCode` classes where the |
| 173 /// corresponding class is given by the `category` field of the Message. |
| 174 /// |
| 175 /// All instances are stored as top-level const variables. |
| 176 /// |
| 177 /// A sample output looks as follows: |
| 178 /// |
| 179 /// const FooCategoryErrorCode EXAMPLE_MESSAGE = const FooCategoryErrorCode( |
| 180 /// "EXAMPLE_MESSAGE", |
| 181 /// "Don't use {0} with {1}", |
| 182 /// "Just don't do it"); |
| 183 void emitAnalyzer() { |
| 184 var input = MESSAGES; |
| 185 var outPath = Platform.script.resolve(analyzerPath).toFilePath(); |
| 186 print("Emitting analyzer:"); |
| 187 print(" Input: ${input.length} entries"); |
| 188 print(" Output: $outPath"); |
| 189 |
| 190 StringBuffer out = new StringBuffer(); |
| 191 out.writeln(dontEditWarning); |
| 192 out.writeln(copyrightHeader); |
| 193 out.writeln("import 'package:analyzer/src/generated/error.dart';"); |
| 194 out.writeln(); |
| 195 input.forEach((name, message) { |
| 196 Category category = message.category; |
| 197 String className = category.name + "Code"; |
| 198 out.writeln("const $className $name = const $className("); |
| 199 out.writeln(" '$name',"); |
| 200 |
| 201 String template = message.template; |
| 202 List holeOrder = message.templateHoleOrder; |
| 203 String analyzerTemplate = convertToAnalyzerTemplate(template, holeOrder); |
| 204 out.write(" "); |
| 205 out.write(escapeString(analyzerTemplate)); |
| 206 out.write(",\n "); |
| 207 out.write(escapeString(message.howToFix)); |
| 208 out.writeln("); // Generated. Don't edit."); |
| 209 }); |
| 210 |
| 211 new File(outPath).writeAsStringSync(out.toString()); |
| 212 print("Emitting analyzer done."); |
| 213 } |
| 214 |
| 215 /// Translates the shared messages in `../lib/shared_messages.dart` to JSON, |
| 216 /// dart2js, and analyzer formats. |
| 217 /// |
| 218 /// Emits the json-output to [jsonPath], the dart2js-output to [dart2jsPath], |
| 219 /// and the analyzer-output to [analyzerPath]. |
| 220 void main() { |
| 221 emitJson(); |
| 222 emitDart2js(); |
| 223 emitAnalyzer(); |
| 224 } |
OLD | NEW |