| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| part of dart._runtime; |
| |
| /// This library defines a set of general javascript utilities for us |
| /// by the Dart runtime. |
| // TODO(ochafik): Rewrite some of these in Dart when possible. |
| |
| defineProperty(obj, name, desc) => |
| JS('', 'Object.defineProperty(#, #, #)', obj, name, desc); |
| |
| getOwnPropertyDescriptor(obj, name) => |
| JS('', 'Object.getOwnPropertyDescriptor(#, #)', obj, name); |
| |
| Iterable getOwnPropertyNames(obj) => |
| JS('', 'Object.getOwnPropertyNames(#)', obj); |
| |
| Iterable getOwnPropertySymbols(obj) => |
| JS('', 'Object.getOwnPropertySymbols(#)', obj); |
| |
| final hasOwnProperty = JS('', 'Object.prototype.hasOwnProperty'); |
| |
| /// This error indicates a strong mode specific failure, other than a type |
| /// assertion failure (TypeError) or CastError. |
| void throwStrongModeError(String message) { |
| JS('', 'debugger'); |
| JS('', 'throw new #(#);', StrongModeErrorImplementation, message); |
| } |
| |
| /// This error indicates a bug in the runtime or the compiler. |
| void throwInternalError(String message) { |
| JS('', 'debugger'); |
| JS('', 'throw Error(#)', message); |
| } |
| |
| getOwnNamesAndSymbols(obj) { |
| var names = getOwnPropertyNames(obj); |
| var symbols = getOwnPropertySymbols(obj); |
| return JS('', '#.concat(#)', names, symbols); |
| } |
| |
| safeGetOwnProperty(obj, String name) { |
| var desc = getOwnPropertyDescriptor(obj, name); |
| if (desc != null) return JS('', '#.value', desc); |
| } |
| |
| /// Defines a lazy property. |
| /// After initial get or set, it will replace itself with a value property. |
| // TODO(jmesserly): reusing descriptor objects has been shown to improve |
| // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). |
| defineLazyProperty(to, name, desc) => JS('', '''(() => { |
| let init = $desc.get; |
| let value = null; |
| |
| function lazySetter(x) { |
| init = null; |
| value = x; |
| } |
| function circularInitError() { |
| $throwInternalError('circular initialization for field ' + $name); |
| } |
| function lazyGetter() { |
| if (init == null) return value; |
| |
| // Compute and store the value, guarding against reentry. |
| let f = init; |
| init = circularInitError; |
| lazySetter(f()); |
| return value; |
| } |
| $desc.get = lazyGetter; |
| $desc.configurable = true; |
| if ($desc.set) $desc.set = lazySetter; |
| return $defineProperty($to, $name, $desc); |
| })()'''); |
| |
| void defineLazy(to, from) => JS('', '''(() => { |
| for (let name of $getOwnNamesAndSymbols($from)) { |
| $defineLazyProperty($to, name, $getOwnPropertyDescriptor($from, name)); |
| } |
| })()'''); |
| |
| defineMemoizedGetter(obj, String name, getter) { |
| return defineLazyProperty(obj, name, JS('', '{get: #}', getter)); |
| } |
| |
| copyTheseProperties(to, from, names) => JS('', '''(() => { |
| for (let i = 0; i < $names.length; ++i) { |
| $copyProperty($to, $from, $names[i]); |
| } |
| return $to; |
| })()'''); |
| |
| copyProperty(to, from, name) { |
| var desc = getOwnPropertyDescriptor(from, name); |
| if (JS('bool', '# == Symbol.iterator', name)) { |
| // On native types, Symbol.iterator may already be present. |
| // TODO(jmesserly): investigate if we still need this. |
| // If so, we need to find a better solution. |
| // See: https://github.com/dart-lang/dev_compiler/issues/487 |
| var existing = getOwnPropertyDescriptor(to, name); |
| if (existing != null) { |
| if (JS('bool', '#.writable', existing)) { |
| JS('', '#[#] = #.value', to, name, desc); |
| } |
| return; |
| } |
| } |
| defineProperty(to, name, desc); |
| } |
| |
| @JSExportName('export') |
| exportProperty(to, from, name) => copyProperty(to, from, name); |
| |
| /// Copy properties from source to destination object. |
| /// This operation is commonly called `mixin` in JS. |
| copyProperties(to, from) { |
| return copyTheseProperties(to, from, getOwnNamesAndSymbols(from)); |
| } |