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