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