OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Defines messages templates and an adapter for TransformLogger to be able | 5 /// Defines messages templates and an adapter for TransformLogger to be able |
6 /// report error messages from transformers and refer to them in a consistent | 6 /// report error messages from transformers and refer to them in a consistent |
7 /// manner long term. | 7 /// manner long term. |
8 library code_transformers.messages; | 8 library code_transformers.messages; |
9 | 9 |
10 // Note: this library purposely doesn't depend on dart:io, dart:html, or barback | 10 // Note: this library purposely doesn't depend on dart:io, dart:html, or barback |
11 // so it can easily be used both in the transformers and in client-side apps | 11 // so it can easily be used both in the transformers and in client-side apps |
12 // (for example in the log_injector). | 12 // (for example in the log_injector). |
13 import 'dart:collection' show LinkedHashMap; | 13 import 'dart:collection' show LinkedHashMap; |
| 14 |
14 import 'package:source_span/source_span.dart'; | 15 import 'package:source_span/source_span.dart'; |
15 | 16 |
16 /// A globally unique identifier for an error message. This identifier should be | 17 /// A globally unique identifier for an error message. This identifier should be |
17 /// stable, that is, it should never change after it is asigned to a particular | 18 /// stable, that is, it should never change after it is asigned to a particular |
18 /// message. That allows us to document our error messages and make them | 19 /// message. That allows us to document our error messages and make them |
19 /// searchable for prosperity. | 20 /// searchable for prosperity. |
20 class MessageId implements Comparable { | 21 class MessageId implements Comparable<MessageId> { |
21 /// Name of the package that declares this message. | 22 /// Name of the package that declares this message. |
22 final String package; | 23 final String package; |
23 | 24 |
24 /// Message identifier number, unique within the package. | 25 /// Message identifier number, unique within the package. |
25 final int id; | 26 final int id; |
26 | 27 |
27 const MessageId(this.package, this.id); | 28 const MessageId(this.package, this.id); |
28 | 29 |
29 static const MessageId NOT_SPECIFIED = const MessageId('unknown', 0); | 30 static const MessageId NOT_SPECIFIED = const MessageId('unknown', 0); |
30 | 31 |
(...skipping 10 matching lines...) Expand all Loading... |
41 } | 42 } |
42 | 43 |
43 /// Creates a new [MessageId] from an encoded value produced via [toJson]. | 44 /// Creates a new [MessageId] from an encoded value produced via [toJson]. |
44 factory MessageId.fromJson(data) { | 45 factory MessageId.fromJson(data) { |
45 var index = data.lastIndexOf('#'); | 46 var index = data.lastIndexOf('#'); |
46 if (index == -1) throw 'Invalid message id: $data'; | 47 if (index == -1) throw 'Invalid message id: $data'; |
47 return new MessageId( | 48 return new MessageId( |
48 data.substring(0, index), int.parse(data.substring(index + 1))); | 49 data.substring(0, index), int.parse(data.substring(index + 1))); |
49 } | 50 } |
50 | 51 |
51 operator ==(MessageId other) => package == other.package && id == other.id; | 52 operator ==(Object other) => |
| 53 other is MessageId && package == other.package && id == other.id; |
| 54 |
52 int get hashCode => 31 * package.hashCode + id; | 55 int get hashCode => 31 * package.hashCode + id; |
53 } | 56 } |
54 | 57 |
55 /// An instance of an error message. These are typically produced from a | 58 /// An instance of an error message. These are typically produced from a |
56 /// [MessageTemplate]. | 59 /// [MessageTemplate]. |
57 class Message { | 60 class Message { |
58 /// A globally unique identifier for this message. | 61 /// A globally unique identifier for this message. |
59 final MessageId id; | 62 final MessageId id; |
60 | 63 |
61 /// A snippet message that is presented to the user. | 64 /// A snippet message that is presented to the user. |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 line: locData['line'], | 160 line: locData['line'], |
158 column: locData['column']); | 161 column: locData['column']); |
159 span = new SourceSpan(start, end, spanData['text']); | 162 span = new SourceSpan(start, end, spanData['text']); |
160 } | 163 } |
161 return new BuildLogEntry( | 164 return new BuildLogEntry( |
162 new Message.fromJson(data['message']), span, data['level']); | 165 new Message.fromJson(data['message']), span, data['level']); |
163 } | 166 } |
164 | 167 |
165 /// Serializes this log entry to JSON. | 168 /// Serializes this log entry to JSON. |
166 Map toJson() { | 169 Map toJson() { |
167 var data = {'level': level, 'message': message.toJson(),}; | 170 var data = { |
| 171 'level': level, |
| 172 'message': message.toJson(), |
| 173 }; |
168 if (span != null) { | 174 if (span != null) { |
169 data['span'] = { | 175 data['span'] = { |
170 'start': { | 176 'start': { |
171 'url': span.start.sourceUrl.toString(), | 177 'url': span.start.sourceUrl.toString(), |
172 'offset': span.start.offset, | 178 'offset': span.start.offset, |
173 'line': span.start.line, | 179 'line': span.start.line, |
174 'column': span.start.column, | 180 'column': span.start.column, |
175 }, | 181 }, |
176 'end': { | 182 'end': { |
177 'url': span.end.sourceUrl.toString(), | 183 'url': span.end.sourceUrl.toString(), |
178 'offset': span.end.offset, | 184 'offset': span.end.offset, |
179 'line': span.end.line, | 185 'line': span.end.line, |
180 'column': span.end.column, | 186 'column': span.end.column, |
181 }, | 187 }, |
182 'text': span.text, | 188 'text': span.text, |
183 }; | 189 }; |
184 } | 190 } |
185 return data; | 191 return data; |
186 } | 192 } |
| 193 |
187 String toString() => '${toJson()}'; | 194 String toString() => '${toJson()}'; |
188 } | 195 } |
189 | 196 |
190 /// A table of entries, that clusters error messages by id. | 197 /// A table of entries, that clusters error messages by id. |
191 class LogEntryTable { | 198 class LogEntryTable { |
192 final Map<MessageId, List<BuildLogEntry>> entries; | 199 final Map<MessageId, List<BuildLogEntry>> entries; |
193 | 200 |
194 LogEntryTable() : entries = new LinkedHashMap(); | 201 LogEntryTable() : entries = new LinkedHashMap(); |
195 | 202 |
196 /// Creates a new [LogEntryTable] from an encoded value produced via [toJson]. | 203 /// Creates a new [LogEntryTable] from an encoded value produced via [toJson]. |
197 factory LogEntryTable.fromJson(Map json) { | 204 factory LogEntryTable.fromJson(Map<String, Iterable> json) { |
198 var res = new LogEntryTable(); | 205 var res = new LogEntryTable(); |
199 for (String key in json.keys) { | 206 for (String key in json.keys) { |
200 var id = new MessageId.fromJson(key); | 207 var id = new MessageId.fromJson(key); |
201 res.entries[id] = | 208 res.entries[id] = |
202 json[key].map((v) => new BuildLogEntry.fromJson(v)).toList(); | 209 json[key].map((v) => new BuildLogEntry.fromJson(v)).toList(); |
203 } | 210 } |
204 return res; | 211 return res; |
205 } | 212 } |
206 | 213 |
207 /// Serializes this entire table as JSON. | 214 /// Serializes this entire table as JSON. |
208 Map toJson() { | 215 Map toJson() { |
209 var res = {}; | 216 var res = {}; |
210 entries.forEach((key, value) { | 217 entries.forEach((key, value) { |
211 res['$key'] = value.map((e) => e.toJson()).toList(); | 218 res['$key'] = value.map((e) => e.toJson()).toList(); |
212 }); | 219 }); |
213 return res; | 220 return res; |
214 } | 221 } |
| 222 |
215 String toString() => '${toJson()}'; | 223 String toString() => '${toJson()}'; |
216 | 224 |
217 void add(BuildLogEntry entry) { | 225 void add(BuildLogEntry entry) { |
218 entries.putIfAbsent(entry.message.id, () => []).add(entry); | 226 entries.putIfAbsent(entry.message.id, () => []).add(entry); |
219 } | 227 } |
| 228 |
220 void addAll(LogEntryTable other) { | 229 void addAll(LogEntryTable other) { |
221 for (var key in other.entries.keys) { | 230 for (var key in other.entries.keys) { |
222 var values = entries.putIfAbsent(key, () => []); | 231 var values = entries.putIfAbsent(key, () => []); |
223 values.addAll(other.entries[key]); | 232 values.addAll(other.entries[key]); |
224 } | 233 } |
225 } | 234 } |
226 } | 235 } |
OLD | NEW |