| // 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 '../js_ast/js_ast.dart' as JS show TypeRef, ClosureTypePrinter; |
| |
| /// Set of closure annotations that can be [toString]ed to a single JsDoc comment. |
| /// See https://developers.google.com/closure/compiler/docs/js-for-compiler |
| /// |
| /// TODO(ochafik): Support inclusion of 'normal' comments (including @param comments). |
| class ClosureAnnotation { |
| final String comment; |
| final bool isConst; |
| final bool isConstructor; |
| final bool isFinal; |
| final bool isNoCollapse; |
| final bool isNoSideEffects; |
| final bool isOverride; |
| final bool isPrivate; |
| final bool isProtected; |
| final bool isStruct; |
| final bool isTypedef; |
| final JS.TypeRef lendsToType; |
| final JS.TypeRef returnType; |
| final JS.TypeRef superType; |
| final JS.TypeRef thisType; |
| final JS.TypeRef throwsType; |
| final JS.TypeRef type; |
| final List<JS.TypeRef> interfaces; |
| final List<String> templates; |
| final Map<String, JS.TypeRef> paramTypes; |
| |
| ClosureAnnotation( |
| {this.comment, |
| this.interfaces: const [], |
| this.isConst: false, |
| this.isConstructor: false, |
| this.isFinal: false, |
| this.isNoCollapse: false, |
| this.isNoSideEffects: false, |
| this.isOverride: false, |
| this.isPrivate: false, |
| this.isProtected: false, |
| this.isStruct: false, |
| this.isTypedef: false, |
| this.lendsToType, |
| this.paramTypes: const {}, |
| this.returnType, |
| this.superType, |
| this.templates: const [], |
| this.thisType, |
| this.throwsType, |
| this.type}); |
| |
| @override |
| int get hashCode => _cachedString.hashCode; |
| |
| @override |
| bool operator ==(other) => |
| other is ClosureAnnotation && _cachedString == other._cachedString; |
| |
| @override |
| String toString([String indent = '']) => |
| _cachedString.replaceAll('\n', '\n$indent'); |
| |
| String _print(JS.TypeRef t) => |
| (new JS.ClosureTypePrinter()..visit(t)).toString(); |
| |
| String __cachedString; |
| String get _cachedString { |
| if (__cachedString == null) { |
| bool isNonWildcard(JS.TypeRef t) => t != null && !t.isAny && !t.isUnknown; |
| |
| var lines = <String>[]; |
| if (comment != null) lines.addAll(comment.split('\n')); |
| if (templates != null && templates.isNotEmpty) { |
| lines.add('@template ${templates.join(', ')}'); |
| } |
| if (thisType != null) lines.add('@this {${_print(thisType)}}'); |
| if (isOverride) lines.add('@override'); |
| if (isNoSideEffects) lines.add('@nosideeffects'); |
| if (isNoCollapse) lines.add('@nocollapse'); |
| if (lendsToType != null) lines.add('@lends {${_print(lendsToType)}}'); |
| |
| { |
| var typeHolders = <String>[]; |
| if (isPrivate) typeHolders.add('@private'); |
| if (isProtected) typeHolders.add('@protected'); |
| if (isFinal) typeHolders.add('@final'); |
| if (isConst) typeHolders.add('@const'); |
| if (isTypedef) typeHolders.add('@typedef'); |
| if (isNonWildcard(type)) { |
| if (typeHolders.isEmpty) typeHolders.add('@type'); |
| typeHolders.add('{${_print(type)}}'); |
| } |
| if (!typeHolders.isEmpty) lines.add(typeHolders.join(' ')); |
| } |
| |
| { |
| List constructorLine = []; |
| if (isConstructor) constructorLine.add('@constructor'); |
| if (isStruct) constructorLine.add('@struct'); |
| if (isNonWildcard(superType)) { |
| constructorLine.add('@extends {${_print(superType)}}'); |
| } |
| |
| if (constructorLine.isNotEmpty) lines.add(constructorLine.join(' ')); |
| } |
| |
| if (interfaces != null) { |
| for (var interface in interfaces) { |
| if (isNonWildcard(interface)) |
| lines.add('@implements {${_print(interface)}}'); |
| } |
| } |
| |
| if (paramTypes != null) { |
| paramTypes.forEach((String paramName, JS.TypeRef paramType) { |
| // Must output params even with wildcard type. |
| lines.add('@param {${_print(paramType)}} $paramName'); |
| }); |
| } |
| if (isNonWildcard(returnType)) |
| lines.add('@return {${_print(returnType)}}'); |
| if (isNonWildcard(throwsType)) |
| lines.add('@throws {${_print(throwsType)}}'); |
| |
| if (lines.length == 0) return ''; |
| if (lines.length == 1) return '/** ${lines.single} */'; |
| __cachedString = '/**\n' + lines.map((l) => ' * $l').join('\n') + '\n */'; |
| } |
| return __cachedString; |
| } |
| } |