OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library pub.asset.serialize; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:isolate'; | |
9 | |
10 import 'package:barback/barback.dart'; | |
11 | |
12 //# if source_maps >=0.9.0 <0.10.0 | |
13 //> import 'package:source_maps/span.dart'; | |
14 //# end | |
15 | |
16 //# if source_span | |
17 import 'package:source_span/source_span.dart'; | |
18 //# end | |
19 | |
20 import 'serialize/exception.dart'; | |
21 import 'utils.dart'; | |
22 | |
23 export 'serialize/aggregate_transform.dart'; | |
24 export 'serialize/exception.dart'; | |
25 export 'serialize/transform.dart'; | |
26 export 'serialize/transformer.dart'; | |
27 | |
28 /// Converts [id] into a serializable map. | |
29 Map serializeId(AssetId id) => {'package': id.package, 'path': id.path}; | |
30 | |
31 /// Converts a serializable map into an [AssetId]. | |
32 AssetId deserializeId(Map id) => new AssetId(id['package'], id['path']); | |
33 | |
34 /// Converts [span] into a serializable map. | |
35 /// | |
36 /// [span] may be a [SourceSpan] or a [Span]. | |
37 Map serializeSpan(span) { | |
38 // TODO(nweiz): convert FileSpans to FileSpans. | |
39 // Handily, this code works for both source_map and source_span spans. | |
40 return { | |
41 'sourceUrl': span.sourceUrl.toString(), | |
42 'start': serializeLocation(span.start), | |
43 'end': serializeLocation(span.end), | |
44 'text': span.text, | |
45 }; | |
46 } | |
47 | |
48 /// Converts a serializable map into a [SourceSpan]. | |
49 SourceSpan deserializeSpan(Map span) { | |
50 return new SourceSpan( | |
51 deserializeLocation(span['start']), | |
52 deserializeLocation(span['end']), | |
53 span['text']); | |
54 } | |
55 | |
56 /// Converts [location] into a serializable map. | |
57 /// | |
58 /// [location] may be a [SourceLocation] or a [SourceLocation]. | |
59 Map serializeLocation(location) { | |
60 //# if source_maps >=0.9.0 <0.10.0 | |
61 //> if (location is Location) { | |
62 //> return { | |
63 //> 'sourceUrl': location.sourceUrl, | |
64 //> 'offset': location.offset, | |
65 //> 'line': location.line, | |
66 //> 'column': location.column | |
67 //> }; | |
68 //> } | |
69 //# end | |
70 | |
71 //# if source_span | |
72 // TODO(nweiz): convert FileLocations to FileLocations. | |
73 if (location is SourceLocation) { | |
74 return { | |
75 'sourceUrl': location.sourceUrl.toString(), | |
76 'offset': location.offset, | |
77 'line': location.line, | |
78 'column': location.column | |
79 }; | |
80 } | |
81 //# end | |
82 | |
83 throw new ArgumentError("Unknown type ${location.runtimeType} for location."); | |
84 } | |
85 | |
86 /// Converts a serializable map into a [Location]. | |
87 SourceLocation deserializeLocation(Map location) { | |
88 return new SourceLocation(location['offset'], | |
89 sourceUrl: location['sourceUrl'], | |
90 line: location['line'], | |
91 column: location['column']); | |
92 } | |
93 | |
94 /// Converts [stream] into a serializable map. | |
95 /// | |
96 /// [serializeEvent] is used to serialize each event from the stream. | |
97 Map serializeStream(Stream stream, serializeEvent(event)) { | |
98 var receivePort = new ReceivePort(); | |
99 var map = {'replyTo': receivePort.sendPort}; | |
100 | |
101 receivePort.first.then((message) { | |
102 var sendPort = message['replyTo']; | |
103 stream.listen((event) { | |
104 sendPort.send({ | |
105 'type': 'event', | |
106 'value': serializeEvent(event) | |
107 }); | |
108 }, onError: (error, stackTrace) { | |
109 sendPort.send({ | |
110 'type': 'error', | |
111 'error': serializeException(error, stackTrace) | |
112 }); | |
113 }, onDone: () => sendPort.send({'type': 'done'})); | |
114 }); | |
115 | |
116 return map; | |
117 } | |
118 | |
119 /// Converts a serializable map into a [Stream]. | |
120 /// | |
121 /// [deserializeEvent] is used to deserialize each event from the stream. | |
122 Stream deserializeStream(Map stream, deserializeEvent(event)) { | |
123 return callbackStream(() { | |
124 var receivePort = new ReceivePort(); | |
125 stream['replyTo'].send({'replyTo': receivePort.sendPort}); | |
126 | |
127 var controller = new StreamController(sync: true); | |
128 receivePort.listen((event) { | |
129 switch (event['type']) { | |
130 case 'event': | |
131 controller.add(deserializeEvent(event['value'])); | |
132 break; | |
133 case 'error': | |
134 var exception = deserializeException(event['error']); | |
135 controller.addError(exception, exception.stackTrace); | |
136 break; | |
137 case 'done': | |
138 controller.close(); | |
139 receivePort.close(); | |
140 break; | |
141 } | |
142 }); | |
143 | |
144 return controller.stream; | |
145 }); | |
146 } | |
147 | |
148 /// Wraps [message] and sends it across [port], then waits for a response which | |
149 /// should be sent using [respond]. | |
150 /// | |
151 /// The returned Future will complete to the value or error returned by | |
152 /// [respond]. | |
153 Future call(SendPort port, message) { | |
154 var receivePort = new ReceivePort(); | |
155 port.send({ | |
156 'message': message, | |
157 'replyTo': receivePort.sendPort | |
158 }); | |
159 | |
160 return receivePort.first.then((response) { | |
161 if (response['type'] == 'success') return response['value']; | |
162 assert(response['type'] == 'error'); | |
163 var exception = deserializeException(response['error']); | |
164 return new Future.error(exception, exception.stackTrace); | |
165 }); | |
166 } | |
167 | |
168 /// Responds to a message sent by [call]. | |
169 /// | |
170 /// [wrappedMessage] is the raw message sent by [call]. This unwraps it and | |
171 /// passes the contents of the message to [callback], then sends the return | |
172 /// value of [callback] back to [call]. If [callback] returns a Future or | |
173 /// throws an error, that will also be sent. | |
174 void respond(wrappedMessage, callback(message)) { | |
175 var replyTo = wrappedMessage['replyTo']; | |
176 new Future.sync(() => callback(wrappedMessage['message'])) | |
177 .then((result) => replyTo.send({'type': 'success', 'value': result})) | |
178 .catchError((error, stackTrace) { | |
179 replyTo.send({ | |
180 'type': 'error', | |
181 'error': serializeException(error, stackTrace) | |
182 }); | |
183 }); | |
184 } | |
OLD | NEW |