diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 99dc0f319..7812e40d9 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,6 +1,7 @@ ## 19.0.1-dev - Do not show async frame errors on evaluation. - [#2073](https://github.com/dart-lang/webdev/pull/2073) +- Refactor code for presenting record instances. - [#2074](https://github.com/dart-lang/webdev/pull/2074) ## 19.0.0 diff --git a/dwds/lib/src/debugging/instance.dart b/dwds/lib/src/debugging/instance.dart index f5f008b2d..9178f67bd 100644 --- a/dwds/lib/src/debugging/instance.dart +++ b/dwds/lib/src/debugging/instance.dart @@ -446,41 +446,24 @@ class InstanceHelper extends Domain { .where((p) => p.name != null && int.tryParse(p.name!) != null) .toList(); - /// The fields for a Dart Record. + /// The field names for a Dart record shape. /// /// Returns a range of [count] fields, if available, starting from /// the [offset]. /// /// If [offset] is `null`, assumes 0 offset. /// If [count] is `null`, return all fields starting from the offset. - Future> _recordFields( - RemoteObject record, { + /// The [shape] object describes the shape using `positionalCount` + /// and `named` fields. + /// + /// Returns list of field names for the record shape. + Future> _recordShapeFields( + RemoteObject shape, { int? offset, int? count, }) async { - // We do this in in awkward way because we want the keys and values, but we - // can't return things by value or some Dart objects will come back as - // values that we need to be RemoteObject, e.g. a List of int. - final expression = ''' - function() { - var sdkUtils = ${globalLoadStrategy.loadModuleSnippet}('dart_sdk').dart; - var shape = sdkUtils.dloadRepl(this, "shape"); - var positionalCount = sdkUtils.dloadRepl(shape, "positionals"); - var named = sdkUtils.dloadRepl(shape, "named"); - named = named == null? null: sdkUtils.dsendRepl(named, "toList", []); - var values = sdkUtils.dloadRepl(this, "values"); - values = sdkUtils.dsendRepl(values, "toList", []); - - return { - positionalCount: positionalCount, - named: named, - values: values - }; - } - '''; - final result = await inspector.jsCallFunctionOn(record, expression, []); final positionalCountObject = - await inspector.loadField(result, 'positionalCount'); + await inspector.loadField(shape, 'positionalCount'); if (positionalCountObject == null || positionalCountObject.value is! int) { _logger.warning( 'Unexpected positional count from record: $positionalCountObject', @@ -488,10 +471,7 @@ class InstanceHelper extends Domain { return []; } - final namedObject = await inspector.loadField(result, 'named'); - final valuesObject = await inspector.loadField(result, 'values'); - - // Collect positional fields in the requested range. + final namedObject = await inspector.loadField(shape, 'named'); final positionalCount = positionalCountObject.value as int; final positionalOffset = offset ?? 0; final positionalAvailable = @@ -519,11 +499,49 @@ class InstanceHelper extends Domain { final namedElements = namedInstance?.elements?.map((e) => e.valueAsString) ?? []; - final fieldNameElements = [ + return [ ...positionalElements, ...namedElements, ]; + } + + /// The fields for a Dart Record. + /// + /// Returns a range of [count] fields, if available, starting from + /// the [offset]. + /// + /// If [offset] is `null`, assumes 0 offset. + /// If [count] is `null`, return all fields starting from the offset. + Future> _recordFields( + RemoteObject record, { + int? offset, + int? count, + }) async { + // We do this in in awkward way because we want the keys and values, but we + // can't return things by value or some Dart objects will come back as + // values that we need to be RemoteObject, e.g. a List of int. + final expression = ''' + function() { + var sdkUtils = ${globalLoadStrategy.loadModuleSnippet}('dart_sdk').dart; + var shape = sdkUtils.dloadRepl(this, "shape"); + var positionalCount = sdkUtils.dloadRepl(shape, "positionals"); + var named = sdkUtils.dloadRepl(shape, "named"); + named = named == null? null: sdkUtils.dsendRepl(named, "toList", []); + var values = sdkUtils.dloadRepl(this, "values"); + values = sdkUtils.dsendRepl(values, "toList", []); + + return { + positionalCount: positionalCount, + named: named, + values: values + }; + } + '''; + final result = await inspector.jsCallFunctionOn(record, expression, []); + final fieldNameElements = + await _recordShapeFields(result, offset: offset, count: count); + final valuesObject = await inspector.loadField(result, 'values'); final valuesInstance = await instanceFor(valuesObject, offset: offset, count: count); final valueElements = valuesInstance?.elements ?? []; @@ -533,11 +551,19 @@ class InstanceHelper extends Domain { return []; } - final fields = []; - Map.fromIterables(fieldNameElements, valueElements).forEach((key, value) { - fields.add(BoundField(name: key, value: value)); + return _elementsToBoundFields(fieldNameElements, valueElements); + } + + /// Create a list of `BoundField`s from field [names] and [values]. + static List _elementsToBoundFields( + List names, + List values, + ) { + final boundFields = []; + Map.fromIterables(names, values).forEach((name, value) { + boundFields.add(BoundField(name: name, value: value)); }); - return fields; + return boundFields; } static int _remainingCount(int collected, int requested) {