fb2d1171e5
Modifies `GeneratedDirectory.outputDirPath` and `GeneratedFile.outputPath` to be relative to the SDK's `pkg` directory rather than relative to the containing package. Accordingly, modifies the `GeneratedContent` methods `check`, `checkAll`, `generate`, `generateAll`, `output`, as well as the `DirectoryContentsComputer` and `FileContentsComputer` callbacks, so that their first parameter is the path to the `pkg` directory rather than the path to the containing package. Also modifies the `readApi` functions in `pkg/analysis_server` and `pkg/analyzer_plugin` to accept a path to the `pkg` directory rather than a path to the containing package, since these functions are called by code generation callbacks. These changes should make code generation logic easier to reason about. They also will make it easier to move the outputs of code generation from one package to another, which will pave the way for some follow-up work in which I intend to start sharing error message representations belonging to `pkg/analyzer`, `pkg/front_end`, and `pkg/_fe_analyzer_shared`. Change-Id: Ia9b369b16f2df931c8a472f91400f2c5a0b8be9d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/438480 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
159 lines
4.9 KiB
Dart
159 lines
4.9 KiB
Dart
// Copyright (c) 2018, 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/html_dom.dart';
|
|
import 'package:analyzer_utilities/html_generator.dart';
|
|
import 'package:analyzer_utilities/tools.dart';
|
|
|
|
import 'api.dart';
|
|
import 'codegen_dart.dart';
|
|
import 'codegen_protocol_constants.dart' show generateConstName;
|
|
import 'from_html.dart';
|
|
|
|
GeneratedFile clientTarget() {
|
|
return GeneratedFile(
|
|
'analysis_server_client/lib/handler/notification_handler.dart',
|
|
(pkgRoot) async {
|
|
var visitor = CodegenNotificationHandlerVisitor(readApi(pkgRoot));
|
|
return visitor.collectCode(visitor.visitApi);
|
|
},
|
|
);
|
|
}
|
|
|
|
String _capitalize(String name) =>
|
|
'${name.substring(0, 1).toUpperCase()}${name.substring(1)}';
|
|
|
|
List<String> _generateDartDoc(Element html) =>
|
|
html.children
|
|
.where((Element elem) => elem.name == 'p')
|
|
.map<String>((Element elem) => innerText(elem).trim())
|
|
.toList();
|
|
|
|
String _generateNotificationMethodName(String domainName, String event) =>
|
|
'on${_capitalize(domainName)}${_capitalize(event)}';
|
|
|
|
String _generateParamTypeName(String domainName, String event) =>
|
|
'${_capitalize(domainName)}${_capitalize(event)}Params';
|
|
|
|
/// Visitor which produces Dart code representing the API.
|
|
class CodegenNotificationHandlerVisitor extends DartCodegenVisitor
|
|
with CodeGenerator {
|
|
CodegenNotificationHandlerVisitor(super.api) {
|
|
codeGeneratorSettings.commentLineLength = 79;
|
|
codeGeneratorSettings.docCommentStartMarker = null;
|
|
codeGeneratorSettings.docCommentLineLeader = '/// ';
|
|
codeGeneratorSettings.docCommentEndMarker = null;
|
|
codeGeneratorSettings.languageName = 'dart';
|
|
}
|
|
|
|
void emitDartdoc(List<String> dartdoc) {
|
|
var first = true;
|
|
for (var paragraph in dartdoc) {
|
|
if (first) {
|
|
first = false;
|
|
} else {
|
|
writeln(' ///');
|
|
}
|
|
for (var line in paragraph.split(RegExp('\r?\n'))) {
|
|
writeln(' /// ${line.trim()}');
|
|
}
|
|
}
|
|
}
|
|
|
|
void emitImports() {
|
|
writeln("import 'package:analysis_server_client/protocol.dart';");
|
|
}
|
|
|
|
void emitNotificationHandler() {
|
|
var visitor = _NotificationVisitor(api)..visitApi();
|
|
var notifications = visitor.notificationConstants;
|
|
notifications.sort((n1, n2) => n1.constName.compareTo(n2.constName));
|
|
|
|
writeln('''
|
|
/// [NotificationHandler] processes analysis server notifications
|
|
/// and dispatches those notifications to different methods based upon
|
|
/// the type of notification. Clients may override
|
|
/// any of the "on<EventName>" methods that are of interest.
|
|
///
|
|
/// Clients may mix-in this class, but may not implement it.
|
|
mixin NotificationHandler {
|
|
void handleEvent(Notification notification) {
|
|
var params = notification.params;
|
|
var decoder = ResponseDecoder(null);
|
|
switch (notification.event) {
|
|
''');
|
|
for (var notification in notifications) {
|
|
writeln(' case ${notification.constName}:');
|
|
writeln(' ${notification.methodName}(');
|
|
writeln(' ${notification.paramsTypeName}');
|
|
writeln(" .fromJson(decoder, 'params', params));");
|
|
writeln(' break;');
|
|
}
|
|
writeln(' default:');
|
|
writeln(' onUnknownNotification(notification.event, params);');
|
|
writeln(' break;');
|
|
writeln(' }');
|
|
writeln(' }');
|
|
for (var notification in notifications) {
|
|
writeln();
|
|
emitDartdoc(notification.dartdoc);
|
|
writeln(' void ${notification.methodName}(');
|
|
writeln(' ${notification.paramsTypeName} params) {');
|
|
writeln(' }');
|
|
}
|
|
writeln();
|
|
writeln(' /// Reports a notification that is not processed');
|
|
writeln(' /// by any other notification handlers.');
|
|
writeln(' void onUnknownNotification(String event, params) {}');
|
|
writeln('}');
|
|
}
|
|
|
|
@override
|
|
void visitApi() {
|
|
outputHeader(year: '2018');
|
|
writeln();
|
|
emitImports();
|
|
emitNotificationHandler();
|
|
}
|
|
}
|
|
|
|
class _Notification {
|
|
final String constName;
|
|
final String methodName;
|
|
final String paramsTypeName;
|
|
final List<String> dartdoc;
|
|
|
|
_Notification(
|
|
this.constName,
|
|
this.methodName,
|
|
this.paramsTypeName,
|
|
this.dartdoc,
|
|
);
|
|
}
|
|
|
|
class _NotificationVisitor extends HierarchicalApiVisitor {
|
|
final notificationConstants = <_Notification>[];
|
|
|
|
_NotificationVisitor(super.api);
|
|
|
|
@override
|
|
void visitNotification(Notification notification) {
|
|
notificationConstants.add(
|
|
_Notification(
|
|
generateConstName(
|
|
notification.domainName,
|
|
'notification',
|
|
notification.event,
|
|
),
|
|
_generateNotificationMethodName(
|
|
notification.domainName,
|
|
notification.event,
|
|
),
|
|
_generateParamTypeName(notification.domainName, notification.event),
|
|
_generateDartDoc(notification.html!),
|
|
),
|
|
);
|
|
}
|
|
}
|