Return only scripts included in a library for library object (#1424)

* Return only scripts included in a library for library object

* Addressed CR comments
diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md
index f960e1b..5a2668f 100644
--- a/dwds/CHANGELOG.md
+++ b/dwds/CHANGELOG.md
@@ -11,6 +11,7 @@
   - Various VM API
   - Hot restart
   - Http request handling exceptions
+- Only return scripts included in the library with Library object.
 - Add `ext.dwds.sendEvent` service extension to dwds so other tools
   can send events to the debugger.
   Event format:
diff --git a/dwds/lib/src/debugging/inspector.dart b/dwds/lib/src/debugging/inspector.dart
index 0130f34..a3e657c 100644
--- a/dwds/lib/src/debugging/inspector.dart
+++ b/dwds/lib/src/debugging/inspector.dart
@@ -45,6 +45,9 @@
   /// Map of [ScriptRef] id to containing [LibraryRef] id.
   final _scriptIdToLibraryId = <String, String>{};
 
+  /// Map of [Library] id to included [ScriptRef]s.
+  final _libraryIdToScriptRefs = <String, List<ScriptRef>>{};
+
   final RemoteDebugger remoteDebugger;
   final Debugger debugger;
   final Isolate isolate;
@@ -232,7 +235,7 @@
       String isolateId, String targetId, String expression,
       {Map<String, String> scope}) async {
     scope ??= {};
-    var library = await _getLibrary(isolateId, targetId);
+    var library = await getLibrary(isolateId, targetId);
     if (library == null) {
       throw UnsupportedError(
           'Evaluate is only supported when `targetId` is a library.');
@@ -341,10 +344,6 @@
   }
 
   Future<Library> getLibrary(String isolateId, String objectId) async {
-    return await _getLibrary(isolateId, objectId);
-  }
-
-  Future<Library> _getLibrary(String isolateId, String objectId) async {
     if (isolateId != isolate.id) return null;
     var libraryRef = await libraryHelper.libraryRefFor(objectId);
     if (libraryRef == null) return null;
@@ -354,7 +353,7 @@
   Future<Obj> getObject(String isolateId, String objectId,
       {int offset, int count}) async {
     try {
-      var library = await _getLibrary(isolateId, objectId);
+      var library = await getLibrary(isolateId, objectId);
       if (library != null) {
         return library;
       }
@@ -410,13 +409,16 @@
 
   /// Returns the [ScriptRef] for the provided Dart server path [uri].
   Future<ScriptRef> scriptRefFor(String uri) async {
-    if (_serverPathToScriptRef.isEmpty) {
-      // TODO(grouma) - populate the server path cache a better way.
-      await getScripts(isolate.id);
-    }
+    await _populateScriptCaches();
     return _serverPathToScriptRef[uri];
   }
 
+  /// Returns the [ScriptRef]s in the library with [libraryId].
+  Future<List<ScriptRef>> scriptRefsForLibrary(String libraryId) async {
+    await _populateScriptCaches();
+    return _libraryIdToScriptRefs[libraryId];
+  }
+
   /// Return the VM SourceReport for the given parameters.
   ///
   /// Currently this implements the 'PossibleBreakpoints' report kind.
@@ -486,8 +488,10 @@
 
   /// Request and cache <ScriptRef>s for all the scripts in the application.
   ///
-  /// This populates [_scriptRefsById], [_scriptIdToLibraryId] and
-  /// [_serverPathToScriptRef]. It is a one-time operation, because if we do a
+  /// This populates [_scriptRefsById], [_scriptIdToLibraryId],
+  /// [_libraryIdToScriptRefs] and [_serverPathToScriptRef].
+  ///
+  /// It is a one-time operation, because if we do a
   /// reload the inspector will get re-created.
   ///
   /// Returns the list of scripts refs cached.
@@ -507,11 +511,13 @@
           for (var part in parts) ScriptRef(uri: part, id: createId())
         ];
         var libraryRef = await libraryHelper.libraryRefFor(uri);
+        _libraryIdToScriptRefs.putIfAbsent(libraryRef.id, () => <ScriptRef>[]);
         for (var scriptRef in scriptRefs) {
           _scriptRefsById[scriptRef.id] = scriptRef;
           _scriptIdToLibraryId[scriptRef.id] = libraryRef.id;
           _serverPathToScriptRef[DartUri(scriptRef.uri, _root).serverPath] =
               scriptRef;
+          _libraryIdToScriptRefs[libraryRef.id].add(scriptRef);
         }
       }
       return _scriptRefsById.values.toList();
diff --git a/dwds/lib/src/debugging/libraries.dart b/dwds/lib/src/debugging/libraries.dart
index a6b3bae..6719cbb 100644
--- a/dwds/lib/src/debugging/libraries.dart
+++ b/dwds/lib/src/debugging/libraries.dart
@@ -118,7 +118,7 @@
         uri: libraryRef.uri,
         debuggable: true,
         dependencies: [],
-        scripts: await inspector.scriptRefs,
+        scripts: await inspector.scriptRefsForLibrary(libraryRef.id),
         variables: [],
         functions: [],
         classes: classRefs,
diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart
index df550d7..33a17f9 100644
--- a/dwds/test/chrome_proxy_service_test.dart
+++ b/dwds/test/chrome_proxy_service_test.dart
@@ -412,7 +412,7 @@
 
       setUp(setCurrentLogWriter);
 
-      test('Libraries', () async {
+      test('root Library', () async {
         expect(rootLibrary, isNotNull);
         // TODO: library names change with kernel dart-lang/sdk#36736
         expect(rootLibrary.uri, endsWith('main.dart'));
@@ -421,6 +421,31 @@
         expect(testClass.name, 'MyTestClass');
       });
 
+      test('Library only contains included scripts', () async {
+        var library =
+            await service.getObject(isolate.id, rootLibrary.id) as Library;
+        expect(library.scripts, hasLength(2));
+        expect(
+            library.scripts,
+            unorderedEquals([
+              predicate((ScriptRef s) =>
+                  s.uri == 'org-dartlang-app:///example/hello_world/main.dart'),
+              predicate((ScriptRef s) =>
+                  s.uri == 'org-dartlang-app:///example/hello_world/part.dart'),
+            ]));
+      });
+
+      test('Can get the same library in parallel', () async {
+        var futures = [
+          service.getObject(isolate.id, rootLibrary.id),
+          service.getObject(isolate.id, rootLibrary.id),
+        ];
+        var results = await Future.wait(futures);
+        var library1 = results[0] as Library;
+        var library2 = results[1] as Library;
+        expect(library1, equals(library2));
+      });
+
       test('Classes', () async {
         var testClass = await service.getObject(
             isolate.id, rootLibrary.classes.first.id) as Class;