[ DAS ] Update widget preview detection to report both file and library URIs

Change-Id: I138a8eb52ee38356f4cf710a7e530bfa7aa9daf4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/490361
Auto-Submit: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Ben Konyi
2026-03-26 09:21:56 -07:00
committed by Commit Queue
parent 907087a744
commit 93ecced96f
5 changed files with 49 additions and 16 deletions
@@ -87,7 +87,7 @@ class FlutterWidgetPreviewsHandler
var node = graph[result.libraryElement.uri]!; var node = graph[result.libraryElement.uri]!;
return success( return success(
FlutterWidgetPreviews( FlutterWidgetPreviews(
scriptUris: [result.uri], scriptUris: node.previews.map((e) => e.scriptUri).toSet().toList(),
previews: node.previews, previews: node.previews,
namespaces: flutterWidgetPreviewDetector.namespaces, namespaces: flutterWidgetPreviewDetector.namespaces,
), ),
@@ -96,6 +96,7 @@ class FlutterWidgetPreviewDetector {
preview.dependencyHasErrors != dependencyHasErrors) { preview.dependencyHasErrors != dependencyHasErrors) {
node.previews[i] = FlutterWidgetPreviewDetails( node.previews[i] = FlutterWidgetPreviewDetails(
scriptUri: preview.scriptUri, scriptUri: preview.scriptUri,
libraryUri: preview.libraryUri,
position: preview.position, position: preview.position,
packageName: preview.packageName, packageName: preview.packageName,
functionName: preview.functionName, functionName: preview.functionName,
@@ -149,7 +150,7 @@ final class LibraryPreviewNode {
void addPreviews({required ResolvedUnitResult unit}) { void addPreviews({required ResolvedUnitResult unit}) {
// Iterate over the compilation unit's AST to find previews. // Iterate over the compilation unit's AST to find previews.
var visitor = _PreviewVisitor( var visitor = _PreviewVisitor(
lib: unit.libraryElement, unit: unit,
previewNode: this, previewNode: this,
namespaceAllocator: namespaceAllocator, namespaceAllocator: namespaceAllocator,
); );
@@ -243,21 +244,26 @@ class _PreviewVisitor extends RecursiveAstVisitor<void> {
ConstructorDeclaration? _currentConstructor; ConstructorDeclaration? _currentConstructor;
MethodDeclaration? _currentMethod; MethodDeclaration? _currentMethod;
late Uri _currentScriptUri;
late CompilationUnit _currentUnit; late ResolvedUnitResult _currentUnit;
final LineInfo _lineInfo;
final Uri _scriptUri;
final Uri _libraryUri;
_PreviewVisitor({ _PreviewVisitor({
required LibraryElement lib, required ResolvedUnitResult unit,
required this.previewNode, required this.previewNode,
required this.namespaceAllocator, required this.namespaceAllocator,
}) : packageName = lib.uri.scheme == 'package' }) : packageName = unit.libraryElement.uri.scheme == 'package'
? lib.uri.pathSegments.first ? unit.libraryElement.uri.pathSegments.first
: null; : null,
_lineInfo = unit.lineInfo,
_scriptUri = Uri.file(unit.path),
_libraryUri = unit.libraryElement.uri;
void findPreviewsInResolvedUnitResult(ResolvedUnitResult unit) { void findPreviewsInResolvedUnitResult(ResolvedUnitResult unit) {
_currentScriptUri = unit.uri; _currentUnit = unit;
_currentUnit = unit.unit; _currentUnit.unit.visitChildren(this);
_currentUnit.visitChildren(this);
} }
bool hasRequiredParams(FormalParameterList? params) { bool hasRequiredParams(FormalParameterList? params) {
@@ -277,8 +283,7 @@ class _PreviewVisitor extends RecursiveAstVisitor<void> {
if (preview == null) { if (preview == null) {
return; return;
} }
LineInfo lineInfo = _currentUnit.lineInfo; CharacterLocation location = _lineInfo.getLocation(node.offset);
CharacterLocation location = lineInfo.getLocation(node.offset);
int line = location.lineNumber; int line = location.lineNumber;
int column = location.columnNumber; int column = location.columnNumber;
var hasError = previewNode.hasErrors; var hasError = previewNode.hasErrors;
@@ -289,7 +294,8 @@ class _PreviewVisitor extends RecursiveAstVisitor<void> {
required bool isWidgetBuilder, required bool isWidgetBuilder,
}) { }) {
return FlutterWidgetPreviewDetails( return FlutterWidgetPreviewDetails(
scriptUri: _currentScriptUri, scriptUri: _scriptUri,
libraryUri: _libraryUri,
position: Position(character: column, line: line), position: Position(character: column, line: line),
packageName: packageName, packageName: packageName,
functionName: functionName, functionName: functionName,
@@ -320,8 +320,13 @@ Widget partPreview() => Text('Part');
expect(result!.previews, hasLength(2)); expect(result!.previews, hasLength(2));
expect(result.previews.any((p) => p.functionName == 'mainPreview'), isTrue); expect(result.previews.any((p) => p.functionName == 'mainPreview'), isTrue);
expect(result.previews.any((p) => p.functionName == 'partPreview'), isTrue); expect(result.previews.any((p) => p.functionName == 'partPreview'), isTrue);
// Use package: URI as observed in the Actual results. expect(result.previews.map((p) => p.libraryUri.toString()).toSet(), {
expect(result.scriptUris.first.toString(), 'package:test/main.dart'); 'package:test/main.dart',
});
expect(result.scriptUris.map((e) => e.toString()), [
'file:///home/my_project/lib/main.dart',
'file:///home/my_project/lib/part.dart',
]);
} }
Future<void> test_pubWorkspace() async { Future<void> test_pubWorkspace() async {
@@ -382,6 +382,13 @@ List<LspEntity> getCustomClasses() {
'The file:// URI pointing to the script in which the ' 'The file:// URI pointing to the script in which the '
'preview is defined.', 'preview is defined.',
), ),
field(
'libraryUri',
type: 'Uri',
comment:
'The unresolved URI pointing to the library in which the '
'preview is defined. This is either a package: or dart: URI.',
),
field( field(
'position', 'position',
type: 'Position', type: 'Position',
@@ -2192,6 +2192,10 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
/// Set to true if `previewAnnotation` represents a `MultiPreview`. /// Set to true if `previewAnnotation` represents a `MultiPreview`.
final bool isMultiPreview; final bool isMultiPreview;
/// The unresolved URI pointing to the library in which the preview is
/// defined. This is either a package: or dart: URI.
final Uri libraryUri;
/// The name of the package in which this annotated preview function was /// The name of the package in which this annotated preview function was
/// defined. /// defined.
/// ///
@@ -2219,6 +2223,7 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
required this.hasError, required this.hasError,
required this.isBuilder, required this.isBuilder,
required this.isMultiPreview, required this.isMultiPreview,
required this.libraryUri,
this.packageName, this.packageName,
required this.position, required this.position,
required this.previewAnnotation, required this.previewAnnotation,
@@ -2231,6 +2236,7 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
hasError, hasError,
isBuilder, isBuilder,
isMultiPreview, isMultiPreview,
libraryUri,
packageName, packageName,
position, position,
previewAnnotation, previewAnnotation,
@@ -2246,6 +2252,7 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
hasError == other.hasError && hasError == other.hasError &&
isBuilder == other.isBuilder && isBuilder == other.isBuilder &&
isMultiPreview == other.isMultiPreview && isMultiPreview == other.isMultiPreview &&
libraryUri == other.libraryUri &&
packageName == other.packageName && packageName == other.packageName &&
position == other.position && position == other.position &&
previewAnnotation == other.previewAnnotation && previewAnnotation == other.previewAnnotation &&
@@ -2260,6 +2267,7 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
result['hasError'] = hasError; result['hasError'] = hasError;
result['isBuilder'] = isBuilder; result['isBuilder'] = isBuilder;
result['isMultiPreview'] = isMultiPreview; result['isMultiPreview'] = isMultiPreview;
result['libraryUri'] = libraryUri.toString();
result['packageName'] = packageName; result['packageName'] = packageName;
result['position'] = position.toJson(); result['position'] = position.toJson();
result['previewAnnotation'] = previewAnnotation; result['previewAnnotation'] = previewAnnotation;
@@ -2292,6 +2300,10 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
allowsUndefined: false, allowsNull: false)) { allowsUndefined: false, allowsNull: false)) {
return false; return false;
} }
if (!_canParseUri(obj, reporter, 'libraryUri',
allowsUndefined: false, allowsNull: false)) {
return false;
}
if (!_canParseString(obj, reporter, 'packageName', if (!_canParseString(obj, reporter, 'packageName',
allowsUndefined: false, allowsNull: true)) { allowsUndefined: false, allowsNull: true)) {
return false; return false;
@@ -2323,6 +2335,8 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
final isBuilder = isBuilderJson as bool; final isBuilder = isBuilderJson as bool;
final isMultiPreviewJson = json['isMultiPreview']; final isMultiPreviewJson = json['isMultiPreview'];
final isMultiPreview = isMultiPreviewJson as bool; final isMultiPreview = isMultiPreviewJson as bool;
final libraryUriJson = json['libraryUri'];
final libraryUri = Uri.parse(libraryUriJson as String);
final packageNameJson = json['packageName']; final packageNameJson = json['packageName'];
final packageName = packageNameJson as String?; final packageName = packageNameJson as String?;
final positionJson = json['position']; final positionJson = json['position'];
@@ -2337,6 +2351,7 @@ class FlutterWidgetPreviewDetails implements ToJsonable {
hasError: hasError, hasError: hasError,
isBuilder: isBuilder, isBuilder: isBuilder,
isMultiPreview: isMultiPreview, isMultiPreview: isMultiPreview,
libraryUri: libraryUri,
packageName: packageName, packageName: packageName,
position: position, position: position,
previewAnnotation: previewAnnotation, previewAnnotation: previewAnnotation,