mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[analysis_server]/[analyzer_plugin] Make all toJson/fromJson methods go through a central converstion for Path<->URI Strings
This change shouldn't change any current behaviour, but means all "FilePath" types in the legacy protocol spec will go through a (currently no-op) conversion. The server will be able to replace this conversion based on client capabilities in a future CL. Because a lot of the generated classes are in analyzer_plugin, this also moves the ClientUriConverter class there. `pkg\analysis_server\test\src\utilities\json_test.dart` contains tests that the toJson/fromJson methods go through the converter recursively (inc. map keys/values/etc.). Change-Id: If5aec884070128eea594540fd25a9017ada86079 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349060 Reviewed-by: Phil Quitslund <pquitslund@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
678b8e8746
commit
8d936d38fc
File diff suppressed because it is too large
Load diff
|
@ -38,7 +38,6 @@ import 'package:analysis_server/src/services/search/search_engine_internal.dart'
|
|||
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/survey_manager.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/user_prompts.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/file_string_sink.dart';
|
||||
import 'package:analysis_server/src/utilities/null_string_sink.dart';
|
||||
import 'package:analysis_server/src/utilities/process.dart';
|
||||
|
@ -76,6 +75,7 @@ import 'package:analyzer/src/util/performance/operation_performance.dart';
|
|||
import 'package:analyzer/src/utilities/extensions/analysis_session.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol.dart';
|
||||
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:meta/meta.dart';
|
||||
|
|
|
@ -12,13 +12,13 @@ import 'package:analysis_server/src/lsp/handlers/handler_reject.dart';
|
|||
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
|
||||
import 'package:analysis_server/src/lsp/progress.dart';
|
||||
import 'package:analysis_server/src/request_handler_mixin.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
import 'package:analyzer/src/utilities/cancellation.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol.dart';
|
||||
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:language_server_protocol/json_parsing.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import 'package:analysis_server/src/server/diagnostic_server.dart';
|
|||
import 'package:analysis_server/src/server/error_notifier.dart';
|
||||
import 'package:analysis_server/src/server/performance.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/flutter.dart';
|
||||
import 'package:analysis_server/src/utilities/process.dart';
|
||||
import 'package:analyzer/dart/analysis/context_locator.dart';
|
||||
|
@ -46,6 +45,7 @@ import 'package:analyzer/src/util/performance/operation_performance.dart';
|
|||
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
|
||||
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
|
||||
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:meta/meta.dart';
|
||||
|
|
|
@ -18,7 +18,6 @@ import 'package:analysis_server/src/protocol_server.dart' as server
|
|||
hide AnalysisError;
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/services/snippets/snippet.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/extensions/string.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart' as server;
|
||||
import 'package:analyzer/error/error.dart' as server;
|
||||
|
@ -30,6 +29,7 @@ import 'package:analyzer/src/dart/analysis/search.dart' as server
|
|||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/collection.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
const languageSourceName = 'dart';
|
||||
|
|
|
@ -316,7 +316,13 @@ class ServerCapabilitiesComputer {
|
|||
clientCapabilities: _server.lspClientCapabilities!,
|
||||
clientConfiguration: _server.lspClientConfiguration,
|
||||
customDartSchemes: _server.uriConverter.supportedNonFileSchemes,
|
||||
dartFilters: _server.uriConverter.filters,
|
||||
dartFilters: [
|
||||
for (var scheme in {
|
||||
'file',
|
||||
..._server.uriConverter.supportedNonFileSchemes
|
||||
})
|
||||
TextDocumentFilterWithScheme(language: 'dart', scheme: scheme)
|
||||
],
|
||||
pluginTypes: pluginTypes,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
import 'package:analysis_server/src/legacy_analysis_server.dart';
|
||||
import 'package:analysis_server/src/lsp/test_macros.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:language_server_protocol/protocol_generated.dart';
|
||||
import 'package:test/expect.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
|
|
@ -8,8 +8,8 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:language_server_protocol/json_parsing.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
|
|
@ -13,7 +13,6 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
|
|||
import 'package:analysis_server/src/plugin/plugin_manager.dart';
|
||||
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
|
||||
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analysis_server/src/utilities/mocks.dart';
|
||||
import 'package:analyzer/instrumentation/instrumentation.dart';
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
|
@ -23,6 +22,7 @@ import 'package:analyzer/src/test_utilities/test_code_format.dart';
|
|||
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
||||
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
|
||||
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:language_server_protocol/json_parsing.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'dart:convert';
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/protocol/protocol_internal.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart';
|
||||
import 'package:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:analyzer/diagnostic/diagnostic.dart';
|
|||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../../tool/codebase/failing_tests.dart';
|
||||
import '../../abstract_context.dart';
|
||||
|
||||
void main() {
|
||||
|
|
230
pkg/analysis_server/test/src/utilities/json_test.dart
Normal file
230
pkg/analysis_server/test/src/utilities/json_test.dart
Normal file
|
@ -0,0 +1,230 @@
|
|||
// Copyright (c) 2024, 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:analysis_server/src/protocol/protocol_internal.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart'
|
||||
show clientUriConverter;
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(JsonTest);
|
||||
defineReflectiveTests(JsonWithConvertedFilePathsTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class JsonTest {
|
||||
final decoder = ResponseDecoder(null);
|
||||
|
||||
void test_fromJson() {
|
||||
var json = {
|
||||
'offset': 0,
|
||||
'length': 1,
|
||||
'label': 'x',
|
||||
};
|
||||
var label = ClosingLabel.fromJson(decoder, '', json);
|
||||
expect(label.label, 'x');
|
||||
expect(label.offset, 0);
|
||||
expect(label.length, 1);
|
||||
}
|
||||
|
||||
void test_toJson() {
|
||||
var closingLabel = ClosingLabel(0, 1, 'x');
|
||||
var json = closingLabel.toJson();
|
||||
|
||||
expect(json, {
|
||||
'offset': 0,
|
||||
'length': 1,
|
||||
'label': 'x',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class JsonWithConvertedFilePathsTest with ResourceProviderMixin {
|
||||
final decoder = ResponseDecoder(null);
|
||||
|
||||
void setUp() {
|
||||
// These tests use a dummy encoder that just prefixes the FilePaths with
|
||||
// "Encoded" and "Decoded" to simplify testing. The real implementation will
|
||||
// convert between file paths and URI strings.
|
||||
clientUriConverter = _PrefixingUriConverter();
|
||||
}
|
||||
|
||||
void tearDown() {
|
||||
// Because this is currently global, restore after the tests.
|
||||
clientUriConverter = ClientUriConverter.noop(pathContext);
|
||||
}
|
||||
|
||||
void test_fromJson_filePath_list() {
|
||||
var json = {
|
||||
'files': ['/my/file/1', '/my/file/2']
|
||||
};
|
||||
var params = AnalysisFlushResultsParams.fromJson(decoder, '', json);
|
||||
expect(params.files, ['Decoded /my/file/1', 'Decoded /my/file/2']);
|
||||
}
|
||||
|
||||
void test_fromJson_filePath_map_keyValue() {
|
||||
var json = {
|
||||
'included': [],
|
||||
'excluded': [],
|
||||
'packageRoots': {
|
||||
'/my/file/key': '/my/file/value',
|
||||
}
|
||||
};
|
||||
var params = AnalysisSetAnalysisRootsParams.fromJson(decoder, '', json);
|
||||
expect(params.packageRoots, {
|
||||
'Decoded /my/file/key': 'Decoded /my/file/value',
|
||||
});
|
||||
}
|
||||
|
||||
void test_fromJson_filePath_map_value_list() {
|
||||
var json = {
|
||||
'subscriptions': {
|
||||
'CLOSING_LABELS': ['/my/file/value']
|
||||
}
|
||||
};
|
||||
var params = AnalysisSetSubscriptionsParams.fromJson(decoder, '', json);
|
||||
expect(params.subscriptions, {
|
||||
AnalysisService.CLOSING_LABELS: ['Decoded /my/file/value'],
|
||||
});
|
||||
}
|
||||
|
||||
void test_fromJson_filePath_nested() {
|
||||
var json = {
|
||||
'fixes': [
|
||||
{
|
||||
'error': {
|
||||
'severity': 'INFO',
|
||||
'type': 'LINT',
|
||||
'location': {
|
||||
'file': '/my/file',
|
||||
'offset': 0,
|
||||
'length': 1,
|
||||
'startLine': 2,
|
||||
'startColumn': 3
|
||||
},
|
||||
'message': 'x',
|
||||
'code': 'y'
|
||||
},
|
||||
'fixes': []
|
||||
}
|
||||
]
|
||||
};
|
||||
var result = EditGetFixesResult.fromJson(decoder, '', json);
|
||||
expect(result.fixes.single.error.location.file, 'Decoded /my/file');
|
||||
}
|
||||
|
||||
void test_fromJson_filePath_topLevel() {
|
||||
var json = {'file': '/my/file', 'labels': []};
|
||||
var params = AnalysisClosingLabelsParams.fromJson(decoder, '', json);
|
||||
expect(params.file, 'Decoded /my/file');
|
||||
}
|
||||
|
||||
void test_toJson_list() {
|
||||
var params = AnalysisFlushResultsParams(['/my/file/1', '/my/file/2']);
|
||||
var json = params.toJson();
|
||||
|
||||
expect(
|
||||
json,
|
||||
{
|
||||
'files': ['Encoded /my/file/1', 'Encoded /my/file/2']
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void test_toJson_map_keyValue() {
|
||||
var params = AnalysisSetAnalysisRootsParams(
|
||||
[],
|
||||
[],
|
||||
packageRoots: {
|
||||
'/my/file/key': '/my/file/value',
|
||||
},
|
||||
);
|
||||
var json = params.toJson();
|
||||
expect(json, {
|
||||
'included': [],
|
||||
'excluded': [],
|
||||
'packageRoots': {
|
||||
'Encoded /my/file/key': 'Encoded /my/file/value',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void test_toJson_map_value_list() {
|
||||
var params = AnalysisSetSubscriptionsParams(
|
||||
{
|
||||
AnalysisService.CLOSING_LABELS: ['/my/file/value'],
|
||||
},
|
||||
);
|
||||
var json = params.toJson();
|
||||
expect(json, {
|
||||
'subscriptions': {
|
||||
'CLOSING_LABELS': ['Encoded /my/file/value']
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void test_toJson_nested() {
|
||||
var result = EditGetFixesResult([
|
||||
AnalysisErrorFixes(
|
||||
AnalysisError(
|
||||
AnalysisErrorSeverity.INFO,
|
||||
AnalysisErrorType.LINT,
|
||||
Location('/my/file', 0, 1, 2, 3),
|
||||
'x',
|
||||
'y',
|
||||
),
|
||||
)
|
||||
]);
|
||||
var json = result.toJson();
|
||||
expect(json, {
|
||||
'fixes': [
|
||||
{
|
||||
'error': {
|
||||
'severity': 'INFO',
|
||||
'type': 'LINT',
|
||||
'location': {
|
||||
'file': 'Encoded /my/file',
|
||||
'offset': 0,
|
||||
'length': 1,
|
||||
'startLine': 2,
|
||||
'startColumn': 3
|
||||
},
|
||||
'message': 'x',
|
||||
'code': 'y'
|
||||
},
|
||||
'fixes': []
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
void test_toJson_topLevel() {
|
||||
var closingLabelParams = AnalysisClosingLabelsParams('/my/file', []);
|
||||
var json = closingLabelParams.toJson();
|
||||
|
||||
expect(
|
||||
json,
|
||||
{'file': 'Encoded /my/file', 'labels': []},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A [ClientUriConverter] that just prefixes the input string for testing.
|
||||
class _PrefixingUriConverter implements ClientUriConverter {
|
||||
@override
|
||||
String fromClientFilePath(String filePathOrUri) => 'Decoded $filePathOrUri';
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
String toClientFilePath(String filePath) => 'Encoded $filePath';
|
||||
}
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'client_uri_converter_test.dart' as client_uri_converter;
|
||||
import 'extensions/test_all.dart' as extensions;
|
||||
import 'flutter_test.dart' as flutter;
|
||||
import 'import_analyzer_test.dart' as import_analyzer;
|
||||
import 'json_test.dart' as json;
|
||||
import 'profiling_test.dart' as profiling;
|
||||
import 'selection_coverage_test.dart' as selection_coverage;
|
||||
import 'selection_test.dart' as selection;
|
||||
|
@ -16,9 +16,9 @@ import 'strings_test.dart' as strings;
|
|||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
client_uri_converter.main();
|
||||
extensions.main();
|
||||
flutter.main();
|
||||
json.main();
|
||||
import_analyzer.main();
|
||||
profiling.main();
|
||||
selection_coverage.main();
|
||||
|
|
|
@ -25,21 +25,31 @@ const Map<String, String> specialElementFlags = {
|
|||
'deprecated': '0x20'
|
||||
};
|
||||
|
||||
GeneratedFile clientTarget(bool responseRequiresRequestTime) {
|
||||
GeneratedFile clientTarget(
|
||||
bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) {
|
||||
return GeneratedFile(
|
||||
'../analysis_server_client/lib/src/protocol/protocol_generated.dart',
|
||||
(String pkgPath) async {
|
||||
var visitor = CodegenProtocolVisitor('analysis_server_client',
|
||||
responseRequiresRequestTime, false, readApi(pkgPath));
|
||||
var visitor = CodegenProtocolVisitor(
|
||||
'analysis_server_client',
|
||||
responseRequiresRequestTime,
|
||||
requiresProtocolJsonMethods,
|
||||
false,
|
||||
readApi(pkgPath));
|
||||
return visitor.collectCode(visitor.visitApi);
|
||||
});
|
||||
}
|
||||
|
||||
GeneratedFile serverTarget(bool responseRequiresRequestTime) {
|
||||
GeneratedFile serverTarget(
|
||||
bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) {
|
||||
return GeneratedFile('lib/protocol/protocol_generated.dart',
|
||||
(String pkgPath) async {
|
||||
var visitor = CodegenProtocolVisitor(path.basename(pkgPath),
|
||||
responseRequiresRequestTime, true, readApi(pkgPath));
|
||||
var visitor = CodegenProtocolVisitor(
|
||||
path.basename(pkgPath),
|
||||
responseRequiresRequestTime,
|
||||
requiresProtocolJsonMethods,
|
||||
true,
|
||||
readApi(pkgPath));
|
||||
return visitor.collectCode(visitor.visitApi);
|
||||
});
|
||||
}
|
||||
|
@ -75,6 +85,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
/// parameter.
|
||||
final bool responseRequiresRequestTime;
|
||||
|
||||
/// A flag indicating whether the classes should have `toProtocolJson` and
|
||||
/// `fromProtocolJson` methods that can handle converting client URIs.
|
||||
final bool requiresProtocolJsonMethods;
|
||||
|
||||
/// A flag indicating whether this generated code is for the server
|
||||
/// (analysis_server) or for the client (analysis_server_client).
|
||||
final bool isServer;
|
||||
|
@ -88,7 +102,7 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
final Map<String, ImpliedType> impliedTypes;
|
||||
|
||||
CodegenProtocolVisitor(this.packageName, this.responseRequiresRequestTime,
|
||||
this.isServer, Api api)
|
||||
this.requiresProtocolJsonMethods, this.isServer, Api api)
|
||||
: toHtmlVisitor = ToHtmlVisitor(api),
|
||||
impliedTypes = computeImpliedTypes(api),
|
||||
super(api) {
|
||||
|
@ -383,6 +397,8 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
writeln("import 'package:$packageName/protocol/protocol.dart';");
|
||||
writeln(
|
||||
"import 'package:$packageName/src/protocol/protocol_internal.dart';");
|
||||
writeln(
|
||||
"import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' show clientUriConverter;");
|
||||
for (var uri in api.types.importUris) {
|
||||
write("import '");
|
||||
write(uri);
|
||||
|
@ -943,6 +959,12 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
return '$typeName.fromJson(jsonDecoder, $jsonPath, $json)';
|
||||
}
|
||||
});
|
||||
} else if (requiresProtocolJsonMethods &&
|
||||
referencedDefinition.name == 'FilePath') {
|
||||
// TODO(dantup): Ensure if the client sends us filepaths instead of
|
||||
// URIs that we generate good error responses.
|
||||
return FromJsonSnippet((jsonPath, json) =>
|
||||
'clientUriConverter.fromClientFilePath(jsonDecoder.decodeString($jsonPath, $json))');
|
||||
} else {
|
||||
return fromJsonCode(referencedType);
|
||||
}
|
||||
|
@ -966,7 +988,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
}
|
||||
} else if (type is TypeMap) {
|
||||
FromJsonCode keyCode;
|
||||
if (dartType(type.keyType) != 'String') {
|
||||
var referencedDefinition = api.types[type.keyType.typeName];
|
||||
if (dartType(type.keyType) != 'String' ||
|
||||
(requiresProtocolJsonMethods &&
|
||||
referencedDefinition?.name == 'FilePath')) {
|
||||
keyCode = fromJsonCode(type.keyType);
|
||||
} else {
|
||||
keyCode = FromJsonIdentity();
|
||||
|
@ -1060,7 +1085,14 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
/// Compute the code necessary to convert [type] to JSON.
|
||||
ToJsonCode toJsonCode(TypeDecl type) {
|
||||
var resolvedType = resolveTypeReferenceChain(type);
|
||||
if (resolvedType is TypeReference) {
|
||||
if (type is TypeReference &&
|
||||
requiresProtocolJsonMethods &&
|
||||
type.typeName == 'FilePath') {
|
||||
return ToJsonSnippet(
|
||||
dartType(type),
|
||||
(String value) => 'clientUriConverter.toClientFilePath($value)',
|
||||
);
|
||||
} else if (resolvedType is TypeReference) {
|
||||
return ToJsonIdentity(dartType(type));
|
||||
} else if (resolvedType is TypeList) {
|
||||
var itemCode = toJsonCode(resolvedType.itemType);
|
||||
|
@ -1072,7 +1104,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
}
|
||||
} else if (resolvedType is TypeMap) {
|
||||
ToJsonCode keyCode;
|
||||
if (dartType(resolvedType.keyType) != 'String') {
|
||||
var referencedDefinition = api.types[resolvedType.keyType.typeName];
|
||||
if (dartType(resolvedType.keyType) != 'String' ||
|
||||
(requiresProtocolJsonMethods &&
|
||||
referencedDefinition?.name == 'FilePath')) {
|
||||
keyCode = toJsonCode(resolvedType.keyType);
|
||||
} else {
|
||||
keyCode = ToJsonIdentity(dartType(resolvedType.keyType));
|
||||
|
|
|
@ -29,8 +29,8 @@ List<GeneratedContent> get allTargets {
|
|||
var targets = <GeneratedContent>[];
|
||||
targets.add(codegen_analysis_server.target);
|
||||
targets.add(codegen_dart_notification_handler.clientTarget());
|
||||
targets.add(codegen_dart_protocol.clientTarget(false));
|
||||
targets.add(codegen_dart_protocol.serverTarget(false));
|
||||
targets.add(codegen_dart_protocol.clientTarget(false, false));
|
||||
targets.add(codegen_dart_protocol.serverTarget(false, true));
|
||||
targets.add(codegen_java_types.targetDir);
|
||||
targets.add(codegen_inttest_methods.target);
|
||||
targets.add(codegen_matchers.target);
|
||||
|
|
|
@ -9,6 +9,8 @@ import 'package:analysis_server_client/src/protocol/protocol_base.dart';
|
|||
import 'package:analysis_server_client/src/protocol/protocol_common.dart';
|
||||
import 'package:analysis_server_client/src/protocol/protocol_generated.dart';
|
||||
|
||||
final clientUriConverter = _ClientUriConverter();
|
||||
|
||||
final Map<String, RefactoringKind> REQUEST_ID_REFACTORING_KINDS =
|
||||
HashMap<String, RefactoringKind>();
|
||||
|
||||
|
@ -462,3 +464,14 @@ abstract class ResponseResult implements HasToJson {
|
|||
/// given [id].
|
||||
Response toResponse(String id);
|
||||
}
|
||||
|
||||
/// A dummy converter with the required API for the copy of protocol classes
|
||||
/// in analysis_server_client.
|
||||
class _ClientUriConverter {
|
||||
// TODO(dantup): Determine whether analysis_server_client needs to support
|
||||
// macro mappings.
|
||||
|
||||
String fromClientFilePath(String filePath) => filePath;
|
||||
|
||||
String toClientFilePath(String filePath) => filePath;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ mixin ResourceProviderMixin {
|
|||
? MemoryResourceProvider(context: path.windows)
|
||||
: MemoryResourceProvider();
|
||||
|
||||
path.Context get pathContext => resourceProvider.pathContext;
|
||||
|
||||
String convertPath(String path) => resourceProvider.convertPath(path);
|
||||
|
||||
void deleteAnalysisOptionsYamlFile(String directoryPath) {
|
||||
|
|
|
@ -2798,7 +2798,8 @@ class Location implements HasToJson {
|
|||
if (json is Map) {
|
||||
String file;
|
||||
if (json.containsKey('file')) {
|
||||
file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
|
||||
file = clientUriConverter.fromClientFilePath(
|
||||
jsonDecoder.decodeString('$jsonPath.file', json['file']));
|
||||
} else {
|
||||
throw jsonDecoder.mismatch(jsonPath, 'file');
|
||||
}
|
||||
|
@ -2847,7 +2848,7 @@ class Location implements HasToJson {
|
|||
@override
|
||||
Map<String, Object> toJson() {
|
||||
var result = <String, Object>{};
|
||||
result['file'] = file;
|
||||
result['file'] = clientUriConverter.toClientFilePath(file);
|
||||
result['offset'] = offset;
|
||||
result['length'] = length;
|
||||
result['startLine'] = startLine;
|
||||
|
@ -3538,7 +3539,8 @@ class Position implements HasToJson {
|
|||
if (json is Map) {
|
||||
String file;
|
||||
if (json.containsKey('file')) {
|
||||
file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
|
||||
file = clientUriConverter.fromClientFilePath(
|
||||
jsonDecoder.decodeString('$jsonPath.file', json['file']));
|
||||
} else {
|
||||
throw jsonDecoder.mismatch(jsonPath, 'file');
|
||||
}
|
||||
|
@ -3557,7 +3559,7 @@ class Position implements HasToJson {
|
|||
@override
|
||||
Map<String, Object> toJson() {
|
||||
var result = <String, Object>{};
|
||||
result['file'] = file;
|
||||
result['file'] = clientUriConverter.toClientFilePath(file);
|
||||
result['offset'] = offset;
|
||||
return result;
|
||||
}
|
||||
|
@ -4390,7 +4392,8 @@ class SourceFileEdit implements HasToJson {
|
|||
if (json is Map) {
|
||||
String file;
|
||||
if (json.containsKey('file')) {
|
||||
file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
|
||||
file = clientUriConverter.fromClientFilePath(
|
||||
jsonDecoder.decodeString('$jsonPath.file', json['file']));
|
||||
} else {
|
||||
throw jsonDecoder.mismatch(jsonPath, 'file');
|
||||
}
|
||||
|
@ -4420,7 +4423,7 @@ class SourceFileEdit implements HasToJson {
|
|||
@override
|
||||
Map<String, Object> toJson() {
|
||||
var result = <String, Object>{};
|
||||
result['file'] = file;
|
||||
result['file'] = clientUriConverter.toClientFilePath(file);
|
||||
result['fileStamp'] = fileStamp;
|
||||
result['edits'] = edits.map((SourceEdit value) => value.toJson()).toList();
|
||||
return result;
|
||||
|
|
|
@ -8,7 +8,16 @@ import 'dart:convert' hide JsonDecoder;
|
|||
import 'package:analyzer_plugin/protocol/protocol.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
/// This can be set by server (or tests) to change into URI mode for all legacy
|
||||
/// protocol JSON.
|
||||
///
|
||||
// TODO(dantup): Consider replacing this global with encoders being passed to
|
||||
// toJson/fromJson methods.
|
||||
var clientUriConverter = ClientUriConverter.noop(path.context);
|
||||
|
||||
final Map<String, RefactoringKind> REQUEST_ID_REFACTORING_KINDS =
|
||||
HashMap<String, RefactoringKind>();
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// 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:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
/// The file suffix used for virtual macro files in the analyzer.
|
||||
|
@ -17,7 +16,7 @@ const macroClientUriScheme = 'dart-macro+file';
|
|||
/// The simplest form of this class simple translates between file paths and
|
||||
/// `file://` URIs but depending on client capabilities some paths/URIs may be
|
||||
/// re-written to support features like virtual files for macros.
|
||||
class ClientUriConverter {
|
||||
abstract class ClientUriConverter {
|
||||
final path.Context _context;
|
||||
|
||||
/// The URI schemes that are supported by this converter.
|
||||
|
@ -29,27 +28,69 @@ class ClientUriConverter {
|
|||
/// The URI schemes that are supported by this converter except 'file'.
|
||||
final Set<String> supportedNonFileSchemes;
|
||||
|
||||
/// A set of document filters for Dart files in the supported schemes.
|
||||
final List<TextDocumentFilterWithScheme> filters;
|
||||
|
||||
/// Creates a converter that does nothing besides translation between file
|
||||
/// paths and `file://` URIs.
|
||||
ClientUriConverter.noop(path.Context context) : this._(context);
|
||||
factory ClientUriConverter.noop(path.Context context) =>
|
||||
_NoOpConverter(context);
|
||||
|
||||
/// Creates a converter that translates paths/URIs for virtual files such as
|
||||
/// those created by macros.
|
||||
ClientUriConverter.withVirtualFileSupport(path.Context context)
|
||||
: this._(context, {macroClientUriScheme});
|
||||
factory ClientUriConverter.withVirtualFileSupport(path.Context context) =>
|
||||
_VirtualFileClientUriConverter(context);
|
||||
|
||||
ClientUriConverter._(this._context, [this.supportedNonFileSchemes = const {}])
|
||||
: supportedSchemes = {'file', ...supportedNonFileSchemes},
|
||||
filters = [
|
||||
for (var scheme in {'file', ...supportedNonFileSchemes})
|
||||
TextDocumentFilterWithScheme(language: 'dart', scheme: scheme)
|
||||
];
|
||||
: supportedSchemes = {'file', ...supportedNonFileSchemes};
|
||||
|
||||
/// Converts client FilePath (which may be a URI or a file path depending on
|
||||
/// client capbilities) into a file path/reference from the analyzer.
|
||||
///
|
||||
/// This is the legacy protocol equiv of [fromClientUri].
|
||||
String fromClientFilePath(String filePathOrUri);
|
||||
|
||||
/// Converts a URI provided by the client into a file path/reference that can
|
||||
/// be used by the analyzer.
|
||||
///
|
||||
/// This is the LSP equiv of [fromClientFilePath].
|
||||
String fromClientUri(Uri uri);
|
||||
|
||||
/// Converts a file path/reference from the analyzer into a client FilePath
|
||||
/// (which may be a URI or a file path depending on client capbilities).
|
||||
///
|
||||
/// This is the legacy protocol equiv of [toClientUri].
|
||||
String toClientFilePath(String filePath);
|
||||
|
||||
/// Converts a file path/reference from the analyzer into a URI to be sent to
|
||||
/// the client.
|
||||
///
|
||||
/// This is the LSP equiv of [toClientFilePath].
|
||||
Uri toClientUri(String filePath);
|
||||
}
|
||||
|
||||
class _NoOpConverter extends ClientUriConverter {
|
||||
_NoOpConverter(super.context) : super._();
|
||||
|
||||
@override
|
||||
String fromClientFilePath(String filePathOrUri) => filePathOrUri;
|
||||
|
||||
@override
|
||||
String fromClientUri(Uri uri) => _context.fromUri(uri);
|
||||
|
||||
@override
|
||||
String toClientFilePath(String filePath) => filePath;
|
||||
|
||||
@override
|
||||
Uri toClientUri(String filePath) => _context.toUri(filePath);
|
||||
}
|
||||
|
||||
class _VirtualFileClientUriConverter extends ClientUriConverter {
|
||||
_VirtualFileClientUriConverter(path.Context context)
|
||||
: super._(context, {macroClientUriScheme});
|
||||
|
||||
@override
|
||||
String fromClientFilePath(String filePathOrUri) =>
|
||||
fromClientUri(Uri.parse(filePathOrUri));
|
||||
|
||||
@override
|
||||
String fromClientUri(Uri uri) {
|
||||
// For URIs with no scheme, assume it was a relative path and provide a
|
||||
// better message than "scheme '' is not supported".
|
||||
|
@ -81,8 +122,10 @@ class ClientUriConverter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a file path/reference from the analyzer into a URI to be sent to
|
||||
/// the client.
|
||||
@override
|
||||
String toClientFilePath(String filePath) => toClientUri(filePath).toString();
|
||||
|
||||
@override
|
||||
Uri toClientUri(String filePath) {
|
||||
// Map '/.../x.macro.dart' onto macro scheme.
|
||||
if (filePath.endsWith(macroClientFileSuffix) &&
|
|
@ -12,6 +12,7 @@ dependencies:
|
|||
dart_style: ^2.2.1
|
||||
pub_semver: ^2.1.0
|
||||
yaml: ^3.1.0
|
||||
path: ^1.9.0
|
||||
|
||||
# We use 'any' version constraints here as we get our package versions from
|
||||
# the dart-lang/sdk repo's DEPS file. Note that this is a special case; the
|
||||
|
@ -22,6 +23,5 @@ dev_dependencies:
|
|||
lints: any
|
||||
linter: any
|
||||
meta: any
|
||||
path: any
|
||||
test_reflective_loader: any
|
||||
test: any
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
// 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:analysis_server/src/utilities/client_uri_converter.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../../tool/codebase/failing_tests.dart';
|
||||
import '../../abstract_single_unit.dart';
|
||||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(ClientUriConverterTest);
|
||||
|
@ -16,7 +14,7 @@ void main() {
|
|||
}
|
||||
|
||||
@reflectiveTest
|
||||
class ClientUriConverterTest extends AbstractSingleUnitTest {
|
||||
class ClientUriConverterTest with ResourceProviderMixin {
|
||||
Future<void> test_noop_fromUri() async {
|
||||
var converter = ClientUriConverter.noop(pathContext);
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'change_builder/test_all.dart' as change_builder;
|
||||
import 'client_uri_converter_test.dart' as client_uri_converter;
|
||||
import 'completion/test_all.dart' as completion;
|
||||
import 'navigation/test_all.dart' as navigation;
|
||||
import 'string_utilities_test.dart' as string_utilities;
|
||||
|
@ -13,6 +14,7 @@ import 'visitors/test_all.dart' as visitors;
|
|||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
change_builder.main();
|
||||
client_uri_converter.main();
|
||||
completion.main();
|
||||
navigation.main();
|
||||
string_utilities.main();
|
||||
|
|
|
@ -25,11 +25,15 @@ const Map<String, String> specialElementFlags = {
|
|||
'deprecated': '0x20'
|
||||
};
|
||||
|
||||
GeneratedFile target(bool responseRequiresRequestTime) {
|
||||
GeneratedFile target(
|
||||
bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) {
|
||||
return GeneratedFile('lib/protocol/protocol_generated.dart',
|
||||
(String pkgPath) async {
|
||||
var visitor = CodegenProtocolVisitor(
|
||||
path.basename(pkgPath), responseRequiresRequestTime, readApi(pkgPath));
|
||||
path.basename(pkgPath),
|
||||
responseRequiresRequestTime,
|
||||
requiresProtocolJsonMethods,
|
||||
readApi(pkgPath));
|
||||
return visitor.collectCode(visitor.visitApi);
|
||||
});
|
||||
}
|
||||
|
@ -65,6 +69,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
/// parameter.
|
||||
final bool responseRequiresRequestTime;
|
||||
|
||||
/// A flag indicating whether the classes should have `toProtocolJson` and
|
||||
/// `fromProtocolJson` methods that can handle converting client URIs.
|
||||
final bool requiresProtocolJsonMethods;
|
||||
|
||||
/// Visitor used to produce doc comments.
|
||||
final ToHtmlVisitor toHtmlVisitor;
|
||||
|
||||
|
@ -73,8 +81,8 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
/// notifications, etc.
|
||||
final Map<String, ImpliedType> impliedTypes;
|
||||
|
||||
CodegenProtocolVisitor(
|
||||
this.packageName, this.responseRequiresRequestTime, Api api)
|
||||
CodegenProtocolVisitor(this.packageName, this.responseRequiresRequestTime,
|
||||
this.requiresProtocolJsonMethods, Api api)
|
||||
: toHtmlVisitor = ToHtmlVisitor(api),
|
||||
impliedTypes = computeImpliedTypes(api),
|
||||
super(api) {
|
||||
|
@ -957,6 +965,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
return '$typeName.fromJson(jsonDecoder, $jsonPath, $json)';
|
||||
}
|
||||
});
|
||||
} else if (requiresProtocolJsonMethods &&
|
||||
referencedDefinition.name == 'FilePath') {
|
||||
return FromJsonSnippet((jsonPath, json) =>
|
||||
'clientUriConverter.fromClientFilePath(jsonDecoder.decodeString($jsonPath, $json))');
|
||||
} else {
|
||||
return fromJsonCode(referencedType);
|
||||
}
|
||||
|
@ -977,7 +989,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
}
|
||||
} else if (type is TypeMap) {
|
||||
FromJsonCode keyCode;
|
||||
if (dartType(type.keyType) != 'String') {
|
||||
var referencedDefinition = api.types[type.keyType.typeName];
|
||||
if (dartType(type.keyType) != 'String' ||
|
||||
(requiresProtocolJsonMethods &&
|
||||
referencedDefinition?.name == 'FilePath')) {
|
||||
keyCode = fromJsonCode(type.keyType);
|
||||
} else {
|
||||
keyCode = FromJsonIdentity();
|
||||
|
@ -1071,7 +1086,14 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
/// Compute the code necessary to convert [type] to JSON.
|
||||
ToJsonCode toJsonCode(TypeDecl type) {
|
||||
var resolvedType = resolveTypeReferenceChain(type);
|
||||
if (resolvedType is TypeReference) {
|
||||
if (type is TypeReference &&
|
||||
requiresProtocolJsonMethods &&
|
||||
type.typeName == 'FilePath') {
|
||||
return ToJsonSnippet(
|
||||
dartType(type),
|
||||
(String value) => 'clientUriConverter.toClientFilePath($value)',
|
||||
);
|
||||
} else if (resolvedType is TypeReference) {
|
||||
return ToJsonIdentity(dartType(type));
|
||||
} else if (resolvedType is TypeList) {
|
||||
var itemCode = toJsonCode(resolvedType.itemType);
|
||||
|
@ -1083,7 +1105,10 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
|
|||
}
|
||||
} else if (resolvedType is TypeMap) {
|
||||
ToJsonCode keyCode;
|
||||
if (dartType(resolvedType.keyType) != 'String') {
|
||||
var referencedDefinition = api.types[resolvedType.keyType.typeName];
|
||||
if (dartType(resolvedType.keyType) != 'String' ||
|
||||
(requiresProtocolJsonMethods &&
|
||||
referencedDefinition?.name == 'FilePath')) {
|
||||
keyCode = toJsonCode(resolvedType.keyType);
|
||||
} else {
|
||||
keyCode = ToJsonIdentity(dartType(resolvedType.keyType));
|
||||
|
|
|
@ -10,19 +10,28 @@ import 'codegen_dart_protocol.dart';
|
|||
import 'from_html.dart';
|
||||
import 'implied_types.dart';
|
||||
|
||||
GeneratedFile clientTarget(bool responseRequiresRequestTime) => GeneratedFile(
|
||||
GeneratedFile clientTarget(
|
||||
bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) =>
|
||||
GeneratedFile(
|
||||
'../analysis_server_client/lib/src/protocol/protocol_common.dart',
|
||||
(String pkgPath) async {
|
||||
var visitor = CodegenCommonVisitor(
|
||||
path.basename(pkgPath), responseRequiresRequestTime, readApi(pkgPath),
|
||||
path.basename(pkgPath),
|
||||
responseRequiresRequestTime,
|
||||
requiresProtocolJsonMethods,
|
||||
readApi(pkgPath),
|
||||
forClient: true);
|
||||
return visitor.collectCode(visitor.visitApi);
|
||||
});
|
||||
|
||||
GeneratedFile pluginTarget(bool responseRequiresRequestTime) =>
|
||||
GeneratedFile pluginTarget(
|
||||
bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) =>
|
||||
GeneratedFile('lib/protocol/protocol_common.dart', (String pkgPath) async {
|
||||
var visitor = CodegenCommonVisitor(path.basename(pkgPath),
|
||||
responseRequiresRequestTime, readApi(pkgPath));
|
||||
var visitor = CodegenCommonVisitor(
|
||||
path.basename(pkgPath),
|
||||
responseRequiresRequestTime,
|
||||
requiresProtocolJsonMethods,
|
||||
readApi(pkgPath));
|
||||
return visitor.collectCode(visitor.visitApi);
|
||||
});
|
||||
|
||||
|
@ -34,8 +43,8 @@ class CodegenCommonVisitor extends CodegenProtocolVisitor {
|
|||
/// Initialize a newly created visitor to generate code in the package with
|
||||
/// the given [packageName] corresponding to the types in the given [api] that
|
||||
/// are common to multiple protocols.
|
||||
CodegenCommonVisitor(
|
||||
super.packageName, super.responseRequiresRequestTime, super.api,
|
||||
CodegenCommonVisitor(super.packageName, super.responseRequiresRequestTime,
|
||||
super.requiresProtocolJsonMethods, super.api,
|
||||
{this.forClient = false});
|
||||
|
||||
@override
|
||||
|
|
|
@ -24,11 +24,11 @@ Future<void> main() async {
|
|||
/// Get a list of all generated targets.
|
||||
List<GeneratedContent> get allTargets {
|
||||
var targets = <GeneratedContent>[];
|
||||
targets.add(codegen_dart_protocol.target(true));
|
||||
targets.add(codegen_dart_protocol.target(true, false));
|
||||
targets.add(codegen_inttest_methods.target);
|
||||
targets.add(codegen_matchers.target);
|
||||
targets.add(codegen_protocol_common.pluginTarget(true));
|
||||
targets.add(codegen_protocol_common.clientTarget(true));
|
||||
targets.add(codegen_protocol_common.pluginTarget(true, true));
|
||||
targets.add(codegen_protocol_common.clientTarget(true, false));
|
||||
targets.add(codegen_protocol_constants.target);
|
||||
targets.add(to_html.target);
|
||||
return targets;
|
||||
|
|
Loading…
Reference in a new issue