| // Copyright (c) 2017, 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. | 
 |  | 
 | import 'package:kernel/kernel.dart'; | 
 | import 'kernel_helpers.dart'; | 
 |  | 
 | /// Returns true if [library] represents any library from `package:js` or is the | 
 | /// internal `dart:_js_helper` library. | 
 | bool _isJSLibrary(Library library) { | 
 |   if (library == null) return false; | 
 |   var uri = library.importUri; | 
 |   var scheme = uri.scheme; | 
 |   return scheme == 'package' && uri.pathSegments[0] == 'js' || | 
 |       scheme == 'dart' && | 
 |           (uri.path == '_js_helper' || uri.path == '_foreign_helper'); | 
 | } | 
 |  | 
 | bool _annotationIsFromJSLibrary(String expectedName, Expression value) { | 
 |   Class c; | 
 |   if (value is ConstructorInvocation) { | 
 |     c = value.target.enclosingClass; | 
 |   } else if (value is StaticGet) { | 
 |     var type = value.target.getterType; | 
 |     if (type is InterfaceType) c = type.classNode; | 
 |   } | 
 |   return c != null && | 
 |       c.name == expectedName && | 
 |       _isJSLibrary(c.enclosingLibrary); | 
 | } | 
 |  | 
 | /// Whether [value] is a `@rest` annotation (to be used on function parameters | 
 | /// to have them compiled as `...` rest params in ES6 outputs). | 
 | bool isJsRestAnnotation(Expression value) => | 
 |     _annotationIsFromJSLibrary('_Rest', value); | 
 |  | 
 | // TODO(jmesserly): Move JsPeerInterface to package:js (see issue #135). | 
 | // TODO(jacobr): The 'JS' annotation is the new, publically accessible one. | 
 | // The 'JsName' annotation is the old one using internally by dart2js and | 
 | // html libraries.  These two concepts will probably merge eventually. | 
 | bool isJSAnnotation(Expression value) => | 
 |     _annotationIsFromJSLibrary('JS', value) || isJSName(value); | 
 |  | 
 | /// Returns [true] if [e] is the `JS` annotation from `package:js`. | 
 | bool isPublicJSAnnotation(Expression value) => | 
 |     _annotationIsFromJSLibrary('JS', value); | 
 |  | 
 | bool _isJSAnonymousAnnotation(Expression value) => | 
 |     _annotationIsFromJSLibrary('_Anonymous', value); | 
 |  | 
 | bool _isBuiltinAnnotation( | 
 |     Expression value, String libraryName, String annotationName) { | 
 |   if (value is ConstructorInvocation) { | 
 |     var c = value.target.enclosingClass; | 
 |     if (c.name == annotationName) { | 
 |       var uri = c.enclosingLibrary.importUri; | 
 |       return uri.scheme == 'dart' && uri.pathSegments[0] == libraryName; | 
 |     } | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | /// Whether [value] is a `@JSExportName` (internal annotation used in SDK | 
 | /// instead of `@JS` from `package:js`). | 
 | bool isJSExportNameAnnotation(Expression value) => | 
 |     _isBuiltinAnnotation(value, '_foreign_helper', 'JSExportName'); | 
 |  | 
 | /// Whether [i] is a `spread` invocation (to be used on function arguments | 
 | /// to have them compiled as `...` spread args in ES6 outputs). | 
 | bool isJSSpreadInvocation(Procedure target) => | 
 |     target.name.name == 'spread' && _isJSLibrary(target.enclosingLibrary); | 
 |  | 
 | bool isJSName(Expression value) => | 
 |     _isBuiltinAnnotation(value, '_js_helper', 'JSName'); | 
 |  | 
 | bool isJsPeerInterface(Expression value) => | 
 |     _isBuiltinAnnotation(value, '_js_helper', 'JsPeerInterface'); | 
 |  | 
 | bool isNativeAnnotation(Expression value) => | 
 |     _isBuiltinAnnotation(value, '_js_helper', 'Native'); | 
 |  | 
 | bool isJSAnonymousType(Class namedClass) { | 
 |   return hasJSInteropAnnotation(namedClass) && | 
 |       findAnnotation(namedClass, _isJSAnonymousAnnotation) != null; | 
 | } | 
 |  | 
 | /// Returns true iff the class has an `@JS(...)` annotation from `package:js`. | 
 | /// | 
 | /// Note: usually [_usesJSInterop] should be used instead of this. | 
 | // | 
 | // TODO(jmesserly): I think almost all uses of this should be replaced with | 
 | // [_usesJSInterop], which also checks that the library is marked with `@JS`. | 
 | // | 
 | // Right now we have inconsistencies: sometimes we'll respect `@JS` on the | 
 | // class itself, other places we require it on the library. Also members are | 
 | // inconsistent: sometimes they need to have `@JS` on them, other times they | 
 | // need to be `external` in an `@JS` class. | 
 | bool hasJSInteropAnnotation(Class c) => c.annotations.any(isPublicJSAnnotation); | 
 |  | 
 | /// Returns true iff this element is a JS interop member. | 
 | /// | 
 | /// The element's library must have `@JS(...)` annotation from `package:js`. | 
 | /// If the element is a class, it must also be marked with `@JS`. Other | 
 | /// elements, such as class members and top-level functions/accessors, should | 
 | /// be marked `external`. | 
 | bool usesJSInterop(NamedNode n) { | 
 |   var library = getLibrary(n); | 
 |   return library != null && | 
 |       library.annotations.any(isPublicJSAnnotation) && | 
 |       (n is Procedure && n.isExternal || | 
 |           n is Class && n.annotations.any(isPublicJSAnnotation)); | 
 | } |