| // 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:analyzer_utilities/tools.dart'; |
| |
| import 'api.dart'; |
| import 'codegen_dart.dart'; |
| import 'from_html.dart'; |
| |
| final GeneratedFile target = GeneratedFile( |
| 'lib/protocol/protocol_constants.dart', (String pkgPath) async { |
| var visitor = CodegenVisitor(readApi(pkgPath)); |
| return visitor.collectCode(visitor.visitApi); |
| }); |
| |
| /// A visitor that produces Dart code defining constants associated with the |
| /// API. |
| class CodegenVisitor extends DartCodegenVisitor with CodeGenerator { |
| CodegenVisitor(Api api) : super(api) { |
| codeGeneratorSettings.commentLineLength = 79; |
| codeGeneratorSettings.docCommentStartMarker = null; |
| codeGeneratorSettings.docCommentLineLeader = '/// '; |
| codeGeneratorSettings.docCommentEndMarker = null; |
| codeGeneratorSettings.languageName = 'dart'; |
| } |
| |
| /// Generate all of the constants associates with the [api]. |
| void generateConstants() { |
| var visitor = _ConstantVisitor(api); |
| visitor.visitApi(); |
| var constants = visitor.constants; |
| constants.sort((first, second) => first.name.compareTo(second.name)); |
| for (var constant in constants) { |
| generateContant(constant); |
| } |
| } |
| |
| /// Generate the given [constant]. |
| void generateContant(_Constant constant) { |
| write('const String '); |
| write(constant.name); |
| write(' = '); |
| write(constant.value); |
| writeln(';'); |
| } |
| |
| @override |
| void visitApi() { |
| outputHeader(year: '2017'); |
| writeln(); |
| generateConstants(); |
| } |
| } |
| |
| /// A representation of a constant that is to be generated. |
| class _Constant { |
| /// The name of the constant. |
| final String name; |
| |
| /// The value of the constant. |
| final String value; |
| |
| /// Initialize a newly created constant. |
| _Constant(this.name, this.value); |
| } |
| |
| /// A visitor that visits an API to compute a list of constants to be generated. |
| class _ConstantVisitor extends HierarchicalApiVisitor { |
| /// The list of constants to be generated. |
| List<_Constant> constants = <_Constant>[]; |
| |
| /// Initialize a newly created visitor to visit the given [api]. |
| _ConstantVisitor(Api api) : super(api); |
| |
| @override |
| void visitNotification(Notification notification) { |
| var domainName = notification.domainName; |
| var event = notification.event; |
| |
| var constantName = _generateName(domainName, 'notification', event); |
| constants.add(_Constant(constantName, "'$domainName.$event'")); |
| _addFieldConstants(constantName, notification.params); |
| } |
| |
| @override |
| void visitRequest(Request request) { |
| var domainName = request.domainName; |
| var method = request.method; |
| |
| var requestConstantName = _generateName(domainName, 'request', method); |
| constants.add(_Constant(requestConstantName, "'$domainName.$method'")); |
| _addFieldConstants(requestConstantName, request.params); |
| |
| var responseConstantName = _generateName(domainName, 'response', method); |
| _addFieldConstants(responseConstantName, request.result); |
| } |
| |
| /// Generate a constant for each of the fields in the given [type], where the |
| /// name of each constant will be composed from the [parentName] and the name |
| /// of the field. |
| void _addFieldConstants(String parentName, TypeObject type) { |
| if (type == null) { |
| return; |
| } |
| type.fields.forEach((TypeObjectField field) { |
| var name = field.name; |
| var components = <String>[]; |
| components.add(parentName); |
| components.addAll(_split(name)); |
| var fieldConstantName = _fromComponents(components); |
| constants.add(_Constant(fieldConstantName, "'$name'")); |
| }); |
| } |
| |
| /// Return a name generated by converting each of the given [components] to an |
| /// uppercase equivalent, then joining them with underscores. |
| String _fromComponents(List<String> components) => |
| components.map((String component) => component.toUpperCase()).join('_'); |
| |
| /// Generate a name from the [domainName], [kind] and [name] components. |
| String _generateName(String domainName, String kind, String name) { |
| var components = <String>[]; |
| components.addAll(_split(domainName)); |
| components.add(kind); |
| components.addAll(_split(name)); |
| return _fromComponents(components); |
| } |
| |
| /// Return the components of the given [string] that are indicated by an upper |
| /// case letter. |
| Iterable<String> _split(String first) { |
| var regExp = RegExp('[A-Z]'); |
| var components = <String>[]; |
| var start = 1; |
| var index = first.indexOf(regExp, start); |
| while (index >= 0) { |
| components.add(first.substring(start - 1, index)); |
| start = index + 1; |
| index = first.indexOf(regExp, start); |
| } |
| components.add(first.substring(start - 1)); |
| return components; |
| } |
| } |