blob: b1a29ae44c8575035a6a09dd790df60073a14dfb [file] [log] [blame]
// 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.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/dart/element/element.dart';
import 'element_helpers.dart';
bool _isJsLibType(String expectedName, Element e) =>
e?.name == expectedName && _isJsLib(e.library);
/// Returns true if [e] represents any library from `package:js` or is the
/// internal `dart:_js_helper` library.
bool _isJsLib(LibraryElement e) {
if (e == null) return false;
var uri = e.source.uri;
if (uri.scheme == 'package' && uri.path.startsWith('js/')) return true;
if (uri.scheme == 'dart') {
// TODO(jmesserly): this needs cleanup: many of the annotations don't exist
// in these libraries.
return uri.path == '_js_helper' || uri.path == '_foreign_helper';
}
return false;
}
/// Whether [value] is a `@rest` annotation (to be used on function parameters
/// to have them compiled as `...` rest params in ES6 outputs).
bool isJsRestAnnotation(DartObjectImpl value) =>
_isJsLibType('_Rest', value.type.element);
/// Whether [i] is a `spread` invocation (to be used on function arguments
/// to have them compiled as `...` spread args in ES6 outputs).
bool isJsSpreadInvocation(MethodInvocation i) =>
_isJsLibType('spread', i.methodName?.staticElement);
// 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(DartObjectImpl value) =>
_isJsLibType('JS', value.type.element) || isJSName(value);
/// Returns [true] if [e] is the `JS` annotation from `package:js`.
bool isPublicJSAnnotation(DartObjectImpl value) =>
_isJsLibType('JS', value.type.element);
bool isJSAnonymousAnnotation(DartObjectImpl value) =>
_isJsLibType('_Anonymous', value.type.element);
/// Whether [value] is a `@JSExportName` (internal annotation used in SDK
/// instead of `@JS` from `package:js`).
bool isJSExportNameAnnotation(DartObjectImpl value) =>
isBuiltinAnnotation(value, '_foreign_helper', 'JSExportName');
/// Whether [value] is a `@JSName` (internal annotation used in dart:html for
/// renaming members).
bool isJSName(DartObjectImpl value) =>
isBuiltinAnnotation(value, '_js_helper', 'JSName');
bool isNotNullAnnotation(DartObjectImpl value) =>
isBuiltinAnnotation(value, '_js_helper', '_NotNull');
bool isNullCheckAnnotation(DartObjectImpl value) =>
isBuiltinAnnotation(value, '_js_helper', '_NullCheck');
bool isUndefinedAnnotation(DartObjectImpl value) =>
isBuiltinAnnotation(value, '_js_helper', '_Undefined');
/// Returns the name value of the `JSExportName` annotation (when compiling
/// the SDK), or `null` if there's none. This is used to control the name
/// under which functions are compiled and exported.
String getJSExportName(Element e) {
if (!e.source.isInSystemLibrary) return null;
e = e is PropertyAccessorElement && e.isSynthetic ? e.variable : e;
return getAnnotationName(e, isJSExportNameAnnotation);
}