OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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 library dart._utils; | 5 library dart._utils; |
6 | 6 |
7 import 'dart:_foreign_helper' show JS; | 7 import 'dart:_foreign_helper' show JS, JsName; |
8 | 8 |
9 /// This library defines a set of general javascript utilities for us | 9 /// This library defines a set of general javascript utilities for us |
10 /// by the Dart runtime. | 10 /// by the Dart runtime. |
11 // TODO(ochafik): Rewrite some of these in Dart when possible. | 11 // TODO(ochafik): Rewrite some of these in Dart when possible. |
12 | 12 |
13 final defineProperty = JS('', 'Object.defineProperty'); | 13 final defineProperty = JS('', 'Object.defineProperty'); |
14 final getOwnPropertyDescriptor = JS('', 'Object.getOwnPropertyDescriptor'); | 14 final getOwnPropertyDescriptor = JS('', 'Object.getOwnPropertyDescriptor'); |
15 final getOwnPropertyNames = JS('', 'Object.getOwnPropertyNames'); | 15 final getOwnPropertyNames = JS('', 'Object.getOwnPropertyNames'); |
16 final getOwnPropertySymbols = JS('', 'Object.getOwnPropertySymbols'); | 16 final getOwnPropertySymbols = JS('', 'Object.getOwnPropertySymbols'); |
17 | 17 |
18 final hasOwnProperty = JS('', 'Object.prototype.hasOwnProperty'); | 18 final hasOwnProperty = JS('', 'Object.prototype.hasOwnProperty'); |
19 | 19 |
20 // TODO(ochafik): Add ES6 class syntax support to JS intrinsics to avoid this. | 20 // TODO(ochafik): Add ES6 class syntax support to JS intrinsics to avoid this. |
21 final StrongModeError = JS('', '''(function() { | 21 final StrongModeError = JS('', '''(function() { |
22 function StrongModeError(message) { | 22 function StrongModeError(message) { |
23 Error.call(this); | 23 Error.call(this); |
24 this.message = message; | 24 this.message = message; |
25 }; | 25 }; |
26 Object.setPrototypeOf(StrongModeError.prototype, Error.prototype); | 26 Object.setPrototypeOf(StrongModeError.prototype, Error.prototype); |
27 return StrongModeError; | 27 return StrongModeError; |
28 })()'''); | 28 })()'''); |
29 | 29 |
30 /// This error indicates a strong mode specific failure. | 30 /// This error indicates a strong mode specific failure. |
31 void throwStrongModeError(String message) => JS('', '''(() => { | 31 void throwStrongModeError(String message) => JS('', '''(() => { |
32 throw new StrongModeError($message); | 32 throw new $StrongModeError($message); |
33 })()'''); | 33 })()'''); |
34 | 34 |
35 /// This error indicates a bug in the runtime or the compiler. | 35 /// This error indicates a bug in the runtime or the compiler. |
36 void throwInternalError(String message) => JS('', '''(() => { | 36 void throwInternalError(String message) => JS('', '''(() => { |
37 throw Error($message); | 37 throw Error($message); |
38 })()'''); | 38 })()'''); |
39 | 39 |
40 // TODO(ochafik): Re-introduce a @JS annotation in the SDK (same as package:js) | 40 @JsName('assert') |
41 // so that this is named 'assert' in JavaScript. | |
42 void assert_(bool condition) => JS('', '''(() => { | 41 void assert_(bool condition) => JS('', '''(() => { |
43 if (!condition) throwInternalError("The compiler is broken: failed assert"); | 42 if (!$condition) $throwInternalError("The compiler is broken: failed assert"); |
44 })()'''); | 43 })()'''); |
45 | 44 |
46 getOwnNamesAndSymbols(obj) => JS('', '''(() => { | 45 getOwnNamesAndSymbols(obj) => JS('', '''(() => { |
47 return getOwnPropertyNames(obj).concat(getOwnPropertySymbols(obj)); | 46 return $getOwnPropertyNames($obj).concat($getOwnPropertySymbols($obj)); |
48 })()'''); | 47 })()'''); |
49 | 48 |
50 safeGetOwnProperty(obj, String name) => JS('', '''(() => { | 49 safeGetOwnProperty(obj, String name) => JS('', '''(() => { |
51 let desc = getOwnPropertyDescriptor($obj, $name); | 50 let desc = $getOwnPropertyDescriptor($obj, $name); |
52 if (desc) return desc.value; | 51 if (desc) return desc.value; |
53 })()'''); | 52 })()'''); |
54 | 53 |
55 /// Defines a lazy property. | 54 /// Defines a lazy property. |
56 /// After initial get or set, it will replace itself with a value property. | 55 /// After initial get or set, it will replace itself with a value property. |
57 // TODO(jmesserly): reusing descriptor objects has been shown to improve | 56 // TODO(jmesserly): reusing descriptor objects has been shown to improve |
58 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). | 57 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). |
59 defineLazyProperty(to, name, desc) => JS('', '''(() => { | 58 defineLazyProperty(to, name, desc) => JS('', '''(() => { |
60 let init = $desc.get; | 59 let init = $desc.get; |
61 let value = null; | 60 let value = null; |
62 | 61 |
63 function lazySetter(x) { | 62 function lazySetter(x) { |
64 init = null; | 63 init = null; |
65 value = x; | 64 value = x; |
66 } | 65 } |
67 function circularInitError() { | 66 function circularInitError() { |
68 throwInternalError('circular initialization for field ' + $name); | 67 $throwInternalError('circular initialization for field ' + $name); |
69 } | 68 } |
70 function lazyGetter() { | 69 function lazyGetter() { |
71 if (init == null) return value; | 70 if (init == null) return value; |
72 | 71 |
73 // Compute and store the value, guarding against reentry. | 72 // Compute and store the value, guarding against reentry. |
74 let f = init; | 73 let f = init; |
75 init = circularInitError; | 74 init = circularInitError; |
76 lazySetter(f()); | 75 lazySetter(f()); |
77 return value; | 76 return value; |
78 } | 77 } |
79 $desc.get = lazyGetter; | 78 $desc.get = lazyGetter; |
80 $desc.configurable = true; | 79 $desc.configurable = true; |
81 if ($desc.set) $desc.set = lazySetter; | 80 if ($desc.set) $desc.set = lazySetter; |
82 return defineProperty($to, $name, $desc); | 81 return $defineProperty($to, $name, $desc); |
83 })()'''); | 82 })()'''); |
84 | 83 |
85 void defineLazy(to, from) => JS('', '''(() => { | 84 void defineLazy(to, from) => JS('', '''(() => { |
86 for (let name of getOwnNamesAndSymbols($from)) { | 85 for (let name of $getOwnNamesAndSymbols($from)) { |
87 defineLazyProperty($to, name, getOwnPropertyDescriptor($from, name)); | 86 $defineLazyProperty($to, name, $getOwnPropertyDescriptor($from, name)); |
88 } | 87 } |
89 })()'''); | 88 })()'''); |
90 | 89 |
91 defineMemoizedGetter(obj, String name, getter) => JS('', '''(() => { | 90 defineMemoizedGetter(obj, String name, getter) => JS('', '''(() => { |
92 return defineLazyProperty($obj, $name, {get: $getter}); | 91 return $defineLazyProperty($obj, $name, {get: $getter}); |
93 })()'''); | 92 })()'''); |
94 | 93 |
95 copyTheseProperties(to, from, names) => JS('', '''(() => { | 94 copyTheseProperties(to, from, names) => JS('', '''(() => { |
96 for (let name of $names) { | 95 for (let name of $names) { |
97 var desc = $getOwnPropertyDescriptor($from, name); | 96 var desc = $getOwnPropertyDescriptor($from, name); |
98 if (desc != void 0) { | 97 if (desc != void 0) { |
99 defineProperty($to, name, desc); | 98 $defineProperty($to, name, desc); |
100 } else { | 99 } else { |
101 defineLazyProperty($to, name, () => $from[name]); | 100 $defineLazyProperty($to, name, () => $from[name]); |
102 } | 101 } |
103 } | 102 } |
104 return $to; | 103 return $to; |
105 })()'''); | 104 })()'''); |
106 | 105 |
107 /// Copy properties from source to destination object. | 106 /// Copy properties from source to destination object. |
108 /// This operation is commonly called `mixin` in JS. | 107 /// This operation is commonly called `mixin` in JS. |
109 copyProperties(to, from) => JS('', '''(() => { | 108 copyProperties(to, from) => JS('', '''(() => { |
110 return $copyTheseProperties($to, $from, $getOwnNamesAndSymbols(from)); | 109 return $copyTheseProperties($to, $from, $getOwnNamesAndSymbols($from)); |
111 })()'''); | 110 })()'''); |
112 | 111 |
113 /// Exports from one Dart module to another. | 112 /// Exports from one Dart module to another. |
114 // TODO(ochafik): Re-introduce a @JS annotation in the SDK (same as package:js) | 113 @JsName('export') |
115 // so that this is named 'export' in JavaScript. | |
116 export_(to, from, show, hide) => JS('', '''(() => { | 114 export_(to, from, show, hide) => JS('', '''(() => { |
117 if ($show == void 0 || $show.length == 0) { | 115 if ($show == void 0 || $show.length == 0) { |
118 $show = $getOwnNamesAndSymbols($from); | 116 $show = $getOwnNamesAndSymbols($from); |
119 } | 117 } |
120 if ($hide != void 0) { | 118 if ($hide != void 0) { |
121 var hideMap = new Set($hide); | 119 var hideMap = new Set($hide); |
122 $show = $show.filter((k) => !hideMap.has(k)); | 120 $show = $show.filter((k) => !hideMap.has(k)); |
123 } | 121 } |
124 return $copyTheseProperties($to, $from, $show); | 122 return $copyTheseProperties($to, $from, $show); |
125 })()'''); | 123 })()'''); |
OLD | NEW |