OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /** | 5 /** |
6 * Support for interoperating with JavaScript. | 6 * Support for interoperating with JavaScript. |
7 * | 7 * |
8 * This library provides access to JavaScript objects from Dart, allowing | 8 * This library provides access to JavaScript objects from Dart, allowing |
9 * Dart code to get and set properties, and call methods of JavaScript objects | 9 * Dart code to get and set properties, and call methods of JavaScript objects |
10 * and invoke JavaScript functions. The library takes care of converting | 10 * and invoke JavaScript functions. The library takes care of converting |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 * var jsMap = new JsObject.jsify({'a': 1, 'b': 2}); | 82 * var jsMap = new JsObject.jsify({'a': 1, 'b': 2}); |
83 * | 83 * |
84 * This expression creates a JavaScript array: | 84 * This expression creates a JavaScript array: |
85 * | 85 * |
86 * var jsArray = new JsObject.jsify([1, 2, 3]); | 86 * var jsArray = new JsObject.jsify([1, 2, 3]); |
87 */ | 87 */ |
88 library dart.js; | 88 library dart.js; |
89 | 89 |
90 import 'dart:collection' show ListMixin; | 90 import 'dart:collection' show ListMixin; |
91 import 'dart:nativewrappers'; | 91 import 'dart:nativewrappers'; |
| 92 import 'dart:math' as math; |
| 93 import 'dart:mirrors' as mirrors; |
| 94 |
| 95 // TODO(jacobr): if we care about unchecked mode in Dartium we need to set this |
| 96 // to false in unchecked mode. |
| 97 final bool _CHECK_JS_INVOCATIONS = true; |
| 98 |
| 99 final _allowedMethods = new Map<Symbol, _DeclarationSet>(); |
| 100 final _allowedGetters = new Map<Symbol, _DeclarationSet>(); |
| 101 final _allowedSetters = new Map<Symbol, _DeclarationSet>(); |
| 102 |
| 103 final Set<Type> _jsInterfaceTypes = new Set<Type>(); |
| 104 Iterable<Type> get jsInterfaceTypes => _jsInterfaceTypes.toList(); |
| 105 |
| 106 bool _finalized = false; |
| 107 |
| 108 class _DeclarationSet { |
| 109 _DeclarationSet() : _methods = <mirrors.MethodMirror>[]; |
| 110 |
| 111 bool checkType(obj, type) { |
| 112 if (obj == null) return true; |
| 113 return mirrors.reflectType(obj.runtimeType).isSubtypeOf(type); |
| 114 } |
| 115 |
| 116 bool checkReturnType(value) { |
| 117 if (value == null) return true; |
| 118 var valueMirror = mirrors.reflectType(value.runtimeType); |
| 119 for (var method in _methods) { |
| 120 if (method.isGetter) { |
| 121 // FIXME: actually check return types for getters that return function |
| 122 // types. |
| 123 return true; |
| 124 } else { |
| 125 if (valueMirror.isSubtypeOf(method.returnType)) return true; |
| 126 } |
| 127 } |
| 128 return false; |
| 129 } |
| 130 |
| 131 bool _checkDeclaration(Invocation invocation, mirrors.MethodMirror method) { |
| 132 if (method.isGetter) { |
| 133 // FIXME: actually check method types against the function type returned |
| 134 // by the getter. |
| 135 return true; |
| 136 } |
| 137 var parameters = method.parameters; |
| 138 var positionalArguments = invocation.positionalArguments; |
| 139 // Too many arguments |
| 140 if (parameters.length < positionalArguments.length) return false; |
| 141 // Too few required arguments. |
| 142 if (parameters.length > positionalArguments.length && |
| 143 !parameters[positionalArguments.length].isOptional) return false; |
| 144 var endPositional = math.min(parameters.length, positionalArguments.length); |
| 145 for (var i = 0; i < endPositional; i++) { |
| 146 if (parameters[i].isNamed) { |
| 147 // Not enough positional arguments. |
| 148 return false; |
| 149 } |
| 150 if (!checkType(invocation.positionalArguments[i], parameters[i].type)) |
| 151 return false; |
| 152 } |
| 153 if (invocation.namedArguments.isNotEmpty) { |
| 154 var startPositional; |
| 155 for (startPositional = parameters.length -1 ; startPositional >= 0; startP
ositional--) { |
| 156 if (!parameters[startPositional].isNamed) break; |
| 157 } |
| 158 startPositional++; |
| 159 |
| 160 for (var name in invocation.namedArguments.keys) { |
| 161 bool match = false; |
| 162 for (var j = startPositional; j < parameters.length; j++) { |
| 163 var p = parameters[j]; |
| 164 if (p.simpleName == name) { |
| 165 if (!checkType(invocation.namedArguments[name], parameters[j].type)) |
| 166 return false; |
| 167 match = true; |
| 168 break; |
| 169 } |
| 170 } |
| 171 if (match == false) |
| 172 return false; |
| 173 } |
| 174 |
| 175 } |
| 176 return true; |
| 177 } |
| 178 |
| 179 bool checkInvocation(Invocation invocation) { |
| 180 for (var method in _methods) { |
| 181 if (_checkDeclaration(invocation, method)) return true; |
| 182 } |
| 183 return false; |
| 184 } |
| 185 |
| 186 void add(mirrors.MethodMirror mirror) { |
| 187 _methods.add(mirror); |
| 188 } |
| 189 |
| 190 final List<mirrors.MethodMirror> _methods; |
| 191 } |
| 192 |
| 193 /** |
| 194 * Temporary method that we hope to remove at some point. Should only be called
by codegen. |
| 195 */ |
| 196 void registerJsInterfaces(List<Type> classes) { |
| 197 if (_finalized == true) { |
| 198 throw 'JSInterop class registration already finalized'; |
| 199 } |
| 200 Map<Symbol, List<mirrors.DeclarationMirror>> allMembers; |
| 201 for (Type type in classes) { |
| 202 if (!_jsInterfaceTypes.add(type)) continue; // Already registered. |
| 203 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); |
| 204 typeMirror.declarations.forEach((symbol, declaration) { |
| 205 if (declaration is mirrors.MethodMirror && !declaration.isStatic) { |
| 206 if (declaration.isGetter) { |
| 207 _allowedGetters.putIfAbsent(symbol, () => new _DeclarationSet()).add(d
eclaration); |
| 208 _allowedMethods.putIfAbsent(symbol, () => new _DeclarationSet()).add(d
eclaration); |
| 209 } else if (declaration.isSetter) { |
| 210 _allowedSetters.putIfAbsent(symbol, () => new _DeclarationSet()).add(d
eclaration); |
| 211 } else if (!declaration.isConstructor) { |
| 212 _allowedMethods.putIfAbsent(symbol, () => new _DeclarationSet()).add(d
eclaration); |
| 213 } |
| 214 } |
| 215 }); |
| 216 } |
| 217 } |
| 218 |
| 219 _finalizeJsInterfaces() native "Js_finalizeJsInterfaces"; |
| 220 |
| 221 /** |
| 222 * Generates a part file defining source code for JsObjectImpl and related |
| 223 * classes. This is needed so that type checks for all registered JavaScript |
| 224 * interop classes pass. |
| 225 */ |
| 226 String _generateJsObjectImplPart() { |
| 227 Iterable<Type> types = jsInterfaceTypes; |
| 228 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>(); |
| 229 var prefixNames = new Set<String>(); |
| 230 var sb = new StringBuffer(); |
| 231 |
| 232 var implements = <String>[]; |
| 233 for (var type in types) { |
| 234 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); |
| 235 mirrors.LibraryMirror libraryMirror = typeMirror.owner; |
| 236 var prefixName; |
| 237 if (libraryPrefixes.containsKey(libraryMirror)) { |
| 238 prefixName = libraryPrefixes[libraryMirror]; |
| 239 } else { |
| 240 var basePrefixName = mirrors.MirrorSystem.getName(libraryMirror.simpleName
); |
| 241 basePrefixName = basePrefixName.replaceAll('.', '_'); |
| 242 if (basePrefixName.isEmpty) basePrefixName = "lib"; |
| 243 prefixName = basePrefixName; |
| 244 var i = 1; |
| 245 while (prefixNames.contains(prefixName)) { |
| 246 prefixName = '$basePrefixName$i'; |
| 247 i++; |
| 248 } |
| 249 prefixNames.add(prefixName); |
| 250 libraryPrefixes[libraryMirror] = prefixName; |
| 251 } |
| 252 implements.add('${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simp
leName)}'); |
| 253 } |
| 254 libraryPrefixes.forEach((libraryMirror, prefix) { |
| 255 sb.writeln('import "${libraryMirror.uri}" as $prefix;'); |
| 256 }); |
| 257 var implementsClause = implements.isEmpty ? "" : "implements ${implements.joi
n(', ')}"; |
| 258 // TODO(jacobr): only certain classes need to be implemented by |
| 259 // Function and Array. |
| 260 sb.write(''' |
| 261 class JsObjectImpl extends JsObject $implementsClause { |
| 262 JsObjectImpl.internal() : super.internal(); |
| 263 } |
| 264 |
| 265 class JsFunctionImpl extends JsFunction $implementsClause { |
| 266 JsFunctionImpl.internal() : super.internal(); |
| 267 } |
| 268 |
| 269 class JsArrayImpl<E> extends JsArray<E> $implementsClause { |
| 270 JsArrayImpl.internal() : super.internal(); |
| 271 } |
| 272 '''); |
| 273 return sb.toString(); |
| 274 } |
| 275 |
| 276 // Start of block of helper methods to emulate JavaScript Array methods on Dart
List. |
| 277 // TODO(jacobr): match JS more closely. |
| 278 String _toStringJs(obj) => '$obj'; |
| 279 |
| 280 // TODO(jacobr): this might not exactly match JS semantics. |
| 281 int _toIntJs(obj) { |
| 282 if (obj is int) return obj; |
| 283 if (obj is num) return obj.toInt(); |
| 284 return num.parse('$obj'.trim(), (_) => 0).toInt(); |
| 285 } |
| 286 |
| 287 // Helper to match the behavior of setting List length in JavaScript. |
| 288 int _setListLength(List list, int len) { |
| 289 for (var i = list.length; i < len; i++) { |
| 290 list.add(null); |
| 291 } |
| 292 return len; |
| 293 } |
| 294 |
| 295 // TODO(jacobr): should we really bother with this method instead of just |
| 296 // shallow copying to a JS array and using the join method? |
| 297 String _arrayJoin(List list, sep) { |
| 298 if (sep == null) { |
| 299 sep = ","; |
| 300 } |
| 301 return list.map((e) => e == null ? "" : e.toString()).join(sep.toString()); |
| 302 } |
| 303 |
| 304 // TODO(jacobr): should we really bother with this method instead of just |
| 305 // shallow copying to a JS array and using the toString method? |
| 306 String _arrayToString(List list) => _arrayJoin(list, ","); |
| 307 |
| 308 int _arrayPush(List list, e) { |
| 309 list.add(e); |
| 310 return list.length; |
| 311 } |
| 312 |
| 313 _arrayPop(List list) => list.removeLast(); |
| 314 |
| 315 // TODO(jacobr): would it be better to just copy input to a JS List |
| 316 // and call Array.concat? |
| 317 List _arrayConcat(List input, List args) { |
| 318 var ret = new List.from(input); |
| 319 for (var e in args) { |
| 320 // TODO(jacobr): should we use Iterable ? |
| 321 if (e is List) { // FIXME use Symbol.isConcatSpreadable |
| 322 ret.addAll(e); |
| 323 } else { |
| 324 ret.add(e); |
| 325 } |
| 326 } |
| 327 return ret; |
| 328 } |
| 329 |
| 330 List _arraySplice(List input, List args) { |
| 331 int start = 0; |
| 332 if (args.length > 0) { |
| 333 var rawStart = _toIntJs(args[0]); |
| 334 if (rawStart < 0) { |
| 335 start = math.max(0, input.length - rawStart); |
| 336 } else { |
| 337 start = math.min(input.length, rawStart); |
| 338 } |
| 339 } |
| 340 var end = start; |
| 341 if (args.length > 1) { |
| 342 var rawDeleteCount = _toIntJs(args[1]); |
| 343 if (rawDeleteCount < 0) rawDeleteCount = 0; |
| 344 end = math.min(input.length, start + rawDeleteCount); |
| 345 } |
| 346 var replacement = []; |
| 347 var removedElements = input.getRange(start, end).toList(); |
| 348 if (args.length > 2) { |
| 349 replacement = args.getRange(2, args.length); |
| 350 } |
| 351 input.replaceRange(start, end, replacement); |
| 352 return removedElements; |
| 353 } |
| 354 |
| 355 List _arrayReverse(List l) { |
| 356 for (var i = 0, j = l.length - 1; i < j; i++, j--) { |
| 357 var tmp = l[i]; |
| 358 l[i] = l[j]; |
| 359 l[j] = tmp; |
| 360 } |
| 361 return l; |
| 362 } |
| 363 |
| 364 _arrayShift(List l) { |
| 365 if (l.isEmpty) return null; // Really want to return JS undefined. |
| 366 return l.removeAt(0); |
| 367 } |
| 368 |
| 369 int _arrayUnshift(List l, List args) { |
| 370 l.insertAll(0, args); |
| 371 return l.length; |
| 372 } |
| 373 |
| 374 _arrayExtend(List l, int newLength) { |
| 375 for (int i = l.length; i < newLength; i++) { |
| 376 // TODO(jacobr): we'd really like to add undefined to better match |
| 377 // JavaScript semantics. |
| 378 l.add(null); |
| 379 } |
| 380 } |
| 381 |
| 382 List _arraySort(List l, rawCompare) { |
| 383 // TODO(jacobr): alternately we could just copy the Array to JavaScript, |
| 384 // invoke the JS sort method and then copy the result back to Dart. |
| 385 Comparator compare; |
| 386 if (rawCompare == null) { |
| 387 compare = (a, b) => _toStringJs(a).compareTo(_toStringJs(b)); |
| 388 } else if (rawCompare is JsFunction) { |
| 389 compare = (a, b) => rawCompare.apply([a, b]); |
| 390 } else { |
| 391 compare = rawCompare; |
| 392 } |
| 393 l.sort(compare); |
| 394 return l; |
| 395 } |
| 396 // End of block of helper methods to emulate JavaScript Array methods on Dart Li
st. |
| 397 |
| 398 /** |
| 399 * Must be called before JS Interfaces can be used safely used and cross cast. |
| 400 */ |
| 401 void finalizeJsInterfaces() { |
| 402 if (_finalized == true) { |
| 403 throw 'JSInterop class registration already finalized'; |
| 404 } |
| 405 _finalized = true; |
| 406 _finalizeJsInterfaces(); |
| 407 } |
92 | 408 |
93 JsObject _cachedContext; | 409 JsObject _cachedContext; |
94 | 410 |
95 JsObject get _context native "Js_context_Callback"; | 411 JsObject get _context native "Js_context_Callback"; |
96 | 412 |
97 JsObject get context { | 413 JsObject get context { |
98 if (_cachedContext == null) { | 414 if (_cachedContext == null) { |
99 _cachedContext = _context; | 415 _cachedContext = _context; |
100 } | 416 } |
101 return _cachedContext; | 417 return _cachedContext; |
102 } | 418 } |
103 | 419 |
104 /** | 420 /** |
105 * Proxies a JavaScript object to Dart. | 421 * Proxies a JavaScript object to Dart. |
106 * | 422 * |
107 * The properties of the JavaScript object are accessible via the `[]` and | 423 * The properties of the JavaScript object are accessible via the `[]` and |
108 * `[]=` operators. Methods are callable via [callMethod]. | 424 * `[]=` operators. Methods are callable via [callMethod]. |
109 */ | 425 */ |
110 class JsObject extends NativeFieldWrapperClass2 { | 426 class JsObject extends NativeFieldWrapperClass2 { |
111 JsObject.internal(); | 427 JsObject.internal(); |
112 | 428 |
113 /** | 429 /** |
114 * Constructs a new JavaScript object from [constructor] and returns a proxy | 430 * Constructs a new JavaScript object from [constructor] and returns a proxy |
115 * to it. | 431 * to it. |
116 */ | 432 */ |
117 factory JsObject(JsFunction constructor, [List arguments]) => _create(construc
tor, arguments); | 433 factory JsObject(JsFunction constructor, [List arguments]) => _create(construc
tor, arguments); |
118 | 434 |
119 static JsObject _create(JsFunction constructor, arguments) native "JsObject_co
nstructorCallback"; | 435 static JsObject _create(JsFunction constructor, arguments) native "JsObject_co
nstructorCallback"; |
120 | 436 |
| 437 _buildArgs(Invocation invocation) { |
| 438 if (invocation.namedArguments.isEmpty) { |
| 439 return invocation.positionalArguments; |
| 440 } else { |
| 441 var varArgs = new Map<String,Object>(); |
| 442 invocation.namedArguments.forEach((symbol, val) { |
| 443 varArgs[mirrors.MirrorSystem.getName(symbol)] = val; |
| 444 }); |
| 445 return invocation.positionalArguments.toList()..add(new JsObject.jsify(var
Args)); |
| 446 } |
| 447 } |
| 448 |
121 /** | 449 /** |
122 * Constructs a [JsObject] that proxies a native Dart object; _for expert use | 450 * Constructs a [JsObject] that proxies a native Dart object; _for expert use |
123 * only_. | 451 * only_. |
124 * | 452 * |
125 * Use this constructor only if you wish to get access to JavaScript | 453 * Use this constructor only if you wish to get access to JavaScript |
126 * properties attached to a browser host object, such as a Node or Blob, that | 454 * properties attached to a browser host object, such as a Node or Blob, that |
127 * is normally automatically converted into a native Dart object. | 455 * is normally automatically converted into a native Dart object. |
128 * | 456 * |
129 * An exception will be thrown if [object] either is `null` or has the type | 457 * An exception will be thrown if [object] either is `null` or has the type |
130 * `bool`, `num`, or `String`. | 458 * `bool`, `num`, or `String`. |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 return _callMethod(method, args); | 553 return _callMethod(method, args); |
226 } catch(e) { | 554 } catch(e) { |
227 if (hasProperty(method)) { | 555 if (hasProperty(method)) { |
228 rethrow; | 556 rethrow; |
229 } else { | 557 } else { |
230 throw new NoSuchMethodError(this, new Symbol(method), args, null); | 558 throw new NoSuchMethodError(this, new Symbol(method), args, null); |
231 } | 559 } |
232 } | 560 } |
233 } | 561 } |
234 | 562 |
| 563 noSuchMethod(Invocation invocation) { |
| 564 throwError() { |
| 565 throw new NoSuchMethodError(this, invocation.memberName, invocation.positi
onalArguments, invocation.namedArguments); |
| 566 } |
| 567 |
| 568 String name = mirrors.MirrorSystem.getName(invocation.memberName); |
| 569 if (invocation.isGetter) { |
| 570 if (_CHECK_JS_INVOCATIONS ) { |
| 571 var matches = _allowedGetters[invocation.memberName]; |
| 572 if (matches == null && !_allowedMethods.containsKey(invocation.memberNam
e)) { |
| 573 throwError(); |
| 574 } |
| 575 var ret = this[name]; |
| 576 if (matches != null && matches.checkReturnType(ret)) return ret; |
| 577 if (ret is Function || (ret is JsFunction /* shouldn't be needed in the
future*/) && _allowedMethods.containsKey(invocation.memberName)) |
| 578 return ret; // Warning: we have not bound "this"... we could type chec
k on the Function but that is of little value in Dart. |
| 579 throwError(); |
| 580 } else { |
| 581 // TODO(jacobr): should we throw if the JavaScript object doesn't have t
he property? |
| 582 return this[name]; |
| 583 } |
| 584 } else if (invocation.isSetter) { |
| 585 if (_CHECK_JS_INVOCATIONS ) { |
| 586 var matches = _allowedSetters[invocation.memberName]; |
| 587 if (!matches.checkInvocation(invocation)) throwError(); |
| 588 } |
| 589 return this[name] = invocation.positionalArguments.first; |
| 590 } else { |
| 591 // TODO(jacobr): also allow calling getters that look like functions. |
| 592 var matches; |
| 593 if (_CHECK_JS_INVOCATIONS ) { |
| 594 matches = _allowedMethods[invocation.memberName]; |
| 595 if (matches == null || !matches.checkInvocation(invocation)) throwError(
); |
| 596 } |
| 597 var ret = this.callMethod(name, _buildArgs(invocation)); |
| 598 if (_CHECK_JS_INVOCATIONS ) { |
| 599 if (!matches.checkReturnType(ret)) throwError(); |
| 600 } |
| 601 return ret; |
| 602 } |
| 603 } |
| 604 |
235 _callMethod(String name, List args) native "JsObject_callMethod"; | 605 _callMethod(String name, List args) native "JsObject_callMethod"; |
236 } | 606 } |
237 | 607 |
238 /** | 608 /** |
239 * Proxies a JavaScript Function object. | 609 * Proxies a JavaScript Function object. |
240 */ | 610 */ |
241 class JsFunction extends JsObject { | 611 class JsFunction extends JsObject implements Function { |
242 JsFunction.internal() : super.internal(); | 612 JsFunction.internal() : super.internal(); |
243 | 613 |
244 /** | 614 /** |
245 * Returns a [JsFunction] that captures its 'this' binding and calls [f] | 615 * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
246 * with the value of this passed as the first argument. | 616 * with the value of this passed as the first argument. |
247 */ | 617 */ |
248 factory JsFunction.withThis(Function f) => _withThis(f); | 618 factory JsFunction.withThis(Function f) => _withThis(f); |
249 | 619 |
250 /** | 620 /** |
251 * Invokes the JavaScript function with arguments [args]. If [thisArg] is | 621 * Invokes the JavaScript function with arguments [args]. If [thisArg] is |
252 * supplied it is the value of `this` for the invocation. | 622 * supplied it is the value of `this` for the invocation. |
253 */ | 623 */ |
254 dynamic apply(List args, {thisArg}) native "JsFunction_apply"; | 624 dynamic apply(List args, {thisArg}) native "JsFunction_apply"; |
255 | 625 |
| 626 noSuchMethod(Invocation invocation) { |
| 627 if (invocation.isMethod && invocation.memberName == #call) { |
| 628 return apply(_buildArgs(invocation)); |
| 629 } |
| 630 return super.noSuchMethod(invocation); |
| 631 } |
| 632 |
256 /** | 633 /** |
257 * Internal only version of apply which uses debugger proxies of Dart objects | 634 * Internal only version of apply which uses debugger proxies of Dart objects |
258 * rather than opaque handles. This method is private because it cannot be | 635 * rather than opaque handles. This method is private because it cannot be |
259 * efficiently implemented in Dart2Js so should only be used by internal | 636 * efficiently implemented in Dart2Js so should only be used by internal |
260 * tools. | 637 * tools. |
261 */ | 638 */ |
262 _applyDebuggerOnly(List args, {thisArg}) native "JsFunction_applyDebuggerOnly"
; | 639 _applyDebuggerOnly(List args, {thisArg}) native "JsFunction_applyDebuggerOnly"
; |
263 | 640 |
264 static JsFunction _withThis(Function f) native "JsFunction_withThis"; | 641 static JsFunction _withThis(Function f) native "JsFunction_withThis"; |
265 } | 642 } |
266 | 643 |
267 /** | 644 /** |
268 * A [List] proxying a JavaScript Array. | 645 * A [List] proxying a JavaScript Array. |
269 */ | 646 */ |
270 class JsArray<E> extends JsObject with ListMixin<E> { | 647 class JsArray<E> extends JsObject with ListMixin<E> { |
| 648 JsArray.internal() : super.internal(); |
271 | 649 |
272 factory JsArray() => _newJsArray(); | 650 factory JsArray() => _newJsArray(); |
273 | 651 |
274 static JsArray _newJsArray() native "JsArray_newJsArray"; | 652 static JsArray _newJsArray() native "JsArray_newJsArray"; |
275 | 653 |
276 factory JsArray.from(Iterable<E> other) => _newJsArrayFromSafeList(new List.fr
om(other)); | 654 factory JsArray.from(Iterable<E> other) => _newJsArrayFromSafeList(new List.fr
om(other)); |
277 | 655 |
278 static JsArray _newJsArrayFromSafeList(List list) native "JsArray_newJsArrayFr
omSafeList"; | 656 static JsArray _newJsArrayFromSafeList(List list) native "JsArray_newJsArrayFr
omSafeList"; |
279 | 657 |
280 _checkIndex(int index, {bool insert: false}) { | 658 _checkIndex(int index, {bool insert: false}) { |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 /** | 751 /** |
374 * Returns a method that can be called with an arbitrary number (for n less | 752 * Returns a method that can be called with an arbitrary number (for n less |
375 * than 11) of arguments without violating Dart type checks. | 753 * than 11) of arguments without violating Dart type checks. |
376 */ | 754 */ |
377 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => | 755 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => |
378 ([a1=_UNDEFINED, a2=_UNDEFINED, a3=_UNDEFINED, a4=_UNDEFINED, | 756 ([a1=_UNDEFINED, a2=_UNDEFINED, a3=_UNDEFINED, a4=_UNDEFINED, |
379 a5=_UNDEFINED, a6=_UNDEFINED, a7=_UNDEFINED, a8=_UNDEFINED, | 757 a5=_UNDEFINED, a6=_UNDEFINED, a7=_UNDEFINED, a8=_UNDEFINED, |
380 a9=_UNDEFINED, a10=_UNDEFINED]) => | 758 a9=_UNDEFINED, a10=_UNDEFINED]) => |
381 jsFunction._applyDebuggerOnly(_stripUndefinedArgs( | 759 jsFunction._applyDebuggerOnly(_stripUndefinedArgs( |
382 [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10])); | 760 [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10])); |
OLD | NEW |