Skip to content

Commit 1e44766

Browse files
committed
Added support for some debugging APIs with the DDC library bundle format
1 parent 3401d30 commit 1e44766

File tree

6 files changed

+192
-11
lines changed

6 files changed

+192
-11
lines changed

dwds/lib/src/debugging/dart_runtime_debugger.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@ class DartRuntimeDebugger {
1818
String _generateJsExpression(
1919
String ddcExpression,
2020
String libraryBundleExpression,
21-
) {
22-
return _useLibraryBundleExpression
23-
? libraryBundleExpression
24-
: ddcExpression;
25-
}
21+
) =>
22+
_useLibraryBundleExpression ? libraryBundleExpression : ddcExpression;
2623

2724
/// Wraps a JS function call with SDK loader logic.
2825
String _wrapWithSdkLoader(String args, String functionCall) {
@@ -199,4 +196,11 @@ class DartRuntimeDebugger {
199196
),
200197
);
201198
}
199+
200+
String invokeExtensionJsExpression(String methodName, String encodedJson) {
201+
return _generateJsExpression(
202+
"${_loadStrategy.loadModuleSnippet}('dart_sdk').developer.invokeExtension('$methodName', JSON.stringify($encodedJson));",
203+
"dartDevEmbedder.debugger.invokeExtension('$methodName', JSON.stringify($encodedJson));",
204+
);
205+
}
202206
}

dwds/lib/src/services/chrome_proxy_service.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -518,10 +518,8 @@ class ChromeProxyService implements VmServiceInterface {
518518
v is String ? v : jsonEncode(v),
519519
),
520520
);
521-
final expression = '''
522-
${globalToolConfiguration.loadStrategy.loadModuleSnippet}("dart_sdk").developer.invokeExtension(
523-
"$method", JSON.stringify(${jsonEncode(stringArgs)}));
524-
''';
521+
final expression = globalToolConfiguration.loadStrategy.dartRuntimeDebugger
522+
.invokeExtensionJsExpression(method, jsonEncode(stringArgs));
525523
final result = await inspector.jsEvaluate(expression, awaitPromise: true);
526524
final decodedResponse =
527525
jsonDecode(result.value as String) as Map<String, dynamic>;

dwds/test/chrome_proxy_service_test.dart renamed to dwds/test/chrome_proxy_service_amd_test.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'dart:async';
1111
import 'dart:convert';
1212
import 'dart:io';
1313

14+
import 'package:dwds/expression_compiler.dart';
1415
import 'package:dwds/src/services/chrome_proxy_service.dart';
1516
import 'package:dwds/src/utilities/dart_uri.dart';
1617
import 'package:dwds/src/utilities/shared.dart';
@@ -29,8 +30,14 @@ import 'fixtures/utilities.dart';
2930
void main() {
3031
// Change to true to see verbose output from the tests.
3132
final debug = false;
32-
33-
final provider = TestSdkConfigurationProvider(verbose: debug);
33+
final moduleFormat = ModuleFormat.amd;
34+
final canaryFeatures = false;
35+
36+
final provider = TestSdkConfigurationProvider(
37+
verbose: debug,
38+
ddcModuleFormat: moduleFormat,
39+
canaryFeatures: canaryFeatures,
40+
);
3441
tearDownAll(provider.dispose);
3542

3643
final context = TestContext(TestProject.test, provider);
@@ -42,6 +49,8 @@ void main() {
4249
testSettings: TestSettings(
4350
enableExpressionEvaluation: true,
4451
verboseCompiler: false,
52+
moduleFormat: provider.ddcModuleFormat,
53+
canaryFeatures: provider.canaryFeatures,
4554
),
4655
);
4756
});
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
@TestOn('vm')
6+
@Tags(['daily'])
7+
@Timeout(Duration(minutes: 2))
8+
library;
9+
10+
import 'dart:convert';
11+
12+
import 'package:dwds/expression_compiler.dart';
13+
import 'package:dwds/src/services/chrome_proxy_service.dart';
14+
import 'package:test/test.dart';
15+
import 'package:test_common/logging.dart';
16+
import 'package:test_common/test_sdk_configuration.dart';
17+
import 'package:vm_service/vm_service.dart';
18+
19+
import 'fixtures/context.dart';
20+
import 'fixtures/project.dart';
21+
import 'fixtures/utilities.dart';
22+
23+
void main() {
24+
// Change to true to see verbose output from the tests.
25+
final debug = false;
26+
final moduleFormat = ModuleFormat.ddc;
27+
final canaryFeatures = true;
28+
final compilationMode = CompilationMode.frontendServer;
29+
30+
final provider = TestSdkConfigurationProvider(
31+
verbose: debug,
32+
ddcModuleFormat: moduleFormat,
33+
canaryFeatures: canaryFeatures,
34+
);
35+
tearDownAll(provider.dispose);
36+
37+
final context = TestContext(TestProject.testDdcLibraryBundle, provider);
38+
39+
group('shared context', () {
40+
setUpAll(() async {
41+
setCurrentLogWriter(debug: debug);
42+
await context.setUp(
43+
testSettings: TestSettings(
44+
enableExpressionEvaluation: true,
45+
verboseCompiler: false,
46+
moduleFormat: provider.ddcModuleFormat,
47+
canaryFeatures: provider.canaryFeatures,
48+
compilationMode: compilationMode,
49+
),
50+
);
51+
});
52+
53+
tearDownAll(() async {
54+
await context.tearDown();
55+
});
56+
57+
group('callServiceExtension', () {
58+
late ChromeProxyService service;
59+
60+
setUp(() {
61+
setCurrentLogWriter(debug: debug);
62+
service = context.service;
63+
});
64+
65+
test(
66+
'success',
67+
() async {
68+
final serviceMethod = 'ext.test.callServiceExtension';
69+
await context.tabConnection.runtime
70+
.evaluate('registerExtension("$serviceMethod");');
71+
72+
// The non-string keys/values get auto json-encoded to match the vm
73+
// behavior.
74+
final args = {
75+
'bool': true,
76+
'list': [1, '2', 3],
77+
'map': {'foo': 'bar'},
78+
'num': 1.0,
79+
'string': 'hello',
80+
1: 2,
81+
false: true,
82+
};
83+
84+
final result =
85+
await service.callServiceExtension(serviceMethod, args: args);
86+
expect(
87+
result.json,
88+
args.map(
89+
(k, v) => MapEntry(
90+
k is String ? k : jsonEncode(k),
91+
v is String ? v : jsonEncode(v),
92+
),
93+
),
94+
);
95+
},
96+
onPlatform: {
97+
'windows':
98+
const Skip('https://github.com/dart-lang/webdev/issues/711'),
99+
},
100+
);
101+
102+
test(
103+
'failure',
104+
() async {
105+
final serviceMethod = 'ext.test.callServiceExtensionWithError';
106+
await context.tabConnection.runtime
107+
.evaluate('registerExtensionWithError("$serviceMethod");');
108+
109+
final errorDetails = {'intentional': 'error'};
110+
expect(
111+
service.callServiceExtension(
112+
serviceMethod,
113+
args: {
114+
'code': '-32001',
115+
'details': jsonEncode(errorDetails),
116+
},
117+
),
118+
throwsA(
119+
predicate(
120+
(dynamic error) =>
121+
error is RPCError &&
122+
error.code == -32001 &&
123+
error.details == jsonEncode(errorDetails),
124+
),
125+
),
126+
);
127+
},
128+
onPlatform: {
129+
'windows':
130+
const Skip('https://github.com/dart-lang/webdev/issues/711'),
131+
},
132+
);
133+
});
134+
});
135+
}

dwds/test/fixtures/project.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ class TestProject {
102102
htmlEntryFileName: 'index.html',
103103
);
104104

105+
static const testDdcLibraryBundle = TestProject._(
106+
packageName: '_test_sound',
107+
packageDirectory: '_testSound',
108+
webAssetsPath: 'example/hello_world',
109+
dartEntryFileName: 'main_ddc_library_bundle.dart',
110+
htmlEntryFileName: 'index.html',
111+
);
112+
105113
static final testScopes = TestProject._(
106114
packageName: '_test_sound',
107115
packageDirectory: '_testSound',
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
import 'dart:developer';
7+
import 'dart:js';
8+
9+
// Create a series of top level objects for tests in
10+
// dwds/test/chrome_proxy_service_ddc_library_bundle_test.dart
11+
12+
void main() async {
13+
context['registerExtension'] = (String method) {
14+
registerExtension(method,
15+
(String method, Map<String, String> parameters) async {
16+
return ServiceExtensionResponse.result(jsonEncode(parameters));
17+
});
18+
};
19+
20+
context['registerExtensionWithError'] = (String method) {
21+
registerExtension(method,
22+
(String method, Map<String, String> parameters) async {
23+
return ServiceExtensionResponse.error(
24+
int.parse(parameters['code']!), parameters['details']!);
25+
});
26+
};
27+
}

0 commit comments

Comments
 (0)