blob: 5b1fe51fae0f1292bb325360da1805716dc4fcd6 [file] [edit]
// 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.
final defineProperty = JS('', 'Object.defineProperty');
final getOwnPropertyDescriptor = JS('', 'Object.getOwnPropertyDescriptor');
final getOwnPropertyNames = JS('', 'Object.getOwnPropertyNames');
final getOwnPropertySymbols = JS('', 'Object.getOwnPropertySymbols');
final hasOwnProperty = JS('', 'Object.prototype.hasOwnProperty');
// TODO(ochafik): Add ES6 class syntax support to JS intrinsics to avoid this.
final StrongModeError = JS('', '''(function() {
function StrongModeError(message) {
Error.call(this);
this.message = message;
};
Object.setPrototypeOf(StrongModeError.prototype, Error.prototype);
return StrongModeError;
})()''');
/// This error indicates a strong mode specific failure.
void throwStrongModeError(String message) => JS('', '''(() => {
debugger;
throw new $StrongModeError($message);
})()''');
/// This error indicates a bug in the runtime or the compiler.
void throwInternalError(String message) => JS('', '''(() => {
debugger;
throw Error($message);
})()''');
getOwnNamesAndSymbols(obj) => JS('', '''(() => {
return $getOwnPropertyNames($obj).concat($getOwnPropertySymbols($obj));
})()''');
safeGetOwnProperty(obj, String name) => JS('', '''(() => {
let desc = $getOwnPropertyDescriptor($obj, $name);
if (desc) return desc.value;
})()''');
/// 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) => JS('', '''(() => {
return $defineLazyProperty($obj, $name, {get: $getter});
})()''');
copyTheseProperties(to, from, names) => JS('', '''(() => {
for (let name of $names) {
var desc = $getOwnPropertyDescriptor($from, name);
if (desc != void 0) {
// On native types, Symbol.iterator may already be present.
if (name == Symbol.iterator && getOwnPropertyDescriptor($to, name)) {
$to[Symbol.iterator] = desc.value;
} else {
$defineProperty($to, name, desc);
}
} else {
$defineLazyProperty($to, name, () => $from[name]);
}
}
return $to;
})()''');
/// Copy properties from source to destination object.
/// This operation is commonly called `mixin` in JS.
copyProperties(to, from) => JS('', '''(() => {
return $copyTheseProperties($to, $from, $getOwnNamesAndSymbols($from));
})()''');
/// Exports from one Dart module to another.
@JSExportName('export')
export_(to, from, show, hide) => JS('', '''(() => {
if ($show == void 0 || $show.length == 0) {
$show = $getOwnNamesAndSymbols($from);
}
if ($hide != void 0) {
var hideMap = new Set($hide);
$show = $show.filter((k) => !hideMap.has(k));
}
return $copyTheseProperties($to, $from, $show);
})()''');