// 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 clientTarget = GeneratedFile( 'analysis_server_client/lib/src/protocol/protocol_constants.dart', (pkgRoot) async { var visitor = _CodegenVisitor(readApi(pkgRoot)); return visitor.collectCode(visitor.visitApi); }, ); final GeneratedFile serverTarget = GeneratedFile( 'analysis_server/lib/protocol/protocol_constants.dart', (pkgRoot) async { var visitor = _CodegenVisitor(readApi(pkgRoot)); return visitor.collectCode(visitor.visitApi); }, ); final _upperCaseLettersPattern = RegExp('[A-Z]'); /// Generate a name from the [domainName], [kind] and [name] components. String generateConstName(String domainName, String kind, String name) { return _fromComponents([..._split(domainName), kind, ..._split(name)]); } /// Returns a name generated by converting each of the given [components] to an /// uppercase equivalent, then joining them with underscores. String _fromComponents(List components) { var joinedName = components .map((s) => '${s[0].toUpperCase()}${s.substring(1)}') .join(); return '${joinedName[0].toLowerCase()}${joinedName.substring(1)}'; } /// Returns the components of the given String that are indicated by an upper /// case letter. Iterable _split(String first) { var components = []; var start = 1; var index = first.indexOf(_upperCaseLettersPattern, start); while (index >= 0) { components.add(first.substring(start - 1, index)); start = index + 1; index = first.indexOf(_upperCaseLettersPattern, start); } components.add(first.substring(start - 1)); return components; } /// A visitor that produces Dart code defining constants associated with the /// API. class _CodegenVisitor extends DartCodegenVisitor with CodeGenerator { new(super.api) { codeGeneratorSettings.commentLineLength = 79; codeGeneratorSettings.docCommentStartMarker = null; codeGeneratorSettings.docCommentLineLeader = '/// '; codeGeneratorSettings.docCommentEndMarker = null; codeGeneratorSettings.languageName = 'dart'; } /// Generate the given [constant]. void generateConstant(_Constant constant) { write('const String '); write(constant.name); write(' = '); write(constant.value); writeln(';'); } /// Generate all of the constants associated with the [api]. void generateConstants() { writeln('// ignore: constant_identifier_names'); writeln("const String PROTOCOL_VERSION = '${api.version}';"); writeln(); var visitor = _ConstantVisitor(api); visitor.visitApi(); var constants = visitor.constants; constants.sort((first, second) => first.name.compareTo(second.name)); for (var constant in constants) { generateConstant(constant); } } @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. new(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]. new(super.api); @override void visitNotification(Notification notification) { var domainName = notification.domainName; var event = notification.event; var constantName = generateConstName(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 = generateConstName(domainName, 'request', method); constants.add(_Constant(requestConstantName, "'$domainName.$method'")); _addFieldConstants(requestConstantName, request.params); var responseConstantName = generateConstName( 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; } for (var field in type.fields) { var name = field.name; var fieldConstantName = _fromComponents([parentName, ..._split(name)]); constants.add(_Constant(fieldConstantName, "'$name'")); } } }