Skip to content

Support for enhanced parts #3892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions lib/src/model/package_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ class PubPackageBuilder implements PackageBuilder {
continue;
}
newFiles.addFilesReferencedBy(resolvedLibrary.element);
for (var unit in resolvedLibrary.units) {
newFiles.addFilesReferencedBy(unit.declaredElement);
}
if (processedLibraries.contains(resolvedLibrary.element)) {
continue;
}
Expand Down Expand Up @@ -548,24 +551,37 @@ class DartDocResolvedLibrary {
extension on Set<String> {
/// Adds [element]'s path and all of its part files' paths to `this`, and
/// recursively adds the paths of all imported and exported libraries.
void addFilesReferencedBy(LibraryOrAugmentationElement? element) {
///
/// [element] must be a [LibraryElement] or [CompilationUnitElement].
void addFilesReferencedBy(Element? element) {
if (element == null) return;

var path = element.source?.fullName;
if (path == null) return;

if (add(path)) {
for (var import in element.libraryImports) {
var libraryImports = switch (element) {
LibraryElement(:var libraryImports) ||
CompilationUnitElement(:var libraryImports) =>
libraryImports,
_ => const <LibraryImportElement>[],
};
for (var import in libraryImports) {
addFilesReferencedBy(import.importedLibrary);
}
for (var export in element.libraryExports) {

var libraryExports = switch (element) {
LibraryElement(:var libraryExports) ||
CompilationUnitElement(:var libraryExports) =>
libraryExports,
_ => const <LibraryExportElement>[],
};
for (var export in libraryExports) {
addFilesReferencedBy(export.exportedLibrary);
}
if (element is LibraryElement) {
for (var part in element.parts
.map((e) => e.uri)
.whereType<DirectiveUriWithUnit>()) {
add(part.source.fullName);
for (var unit in element.units) {
addFilesReferencedBy(unit);
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion lib/src/model/package_graph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,12 @@ class PackageGraph with CommentReferable, Nameable {
alreadyTagged.add(key);
// Mark that `publicLibrary` exports `libraryElement`.
_libraryExports.putIfAbsent(libraryElement, () => {}).add(publicLibrary);
for (var exportedElement in libraryElement.libraryExports) {

var exported = [
...libraryElement.libraryExports,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically units provide all the exports and imports that can be in the library.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah it looks like you're right; I didn't test this with new unit tests, but they look good. Thanks

for (var unit in libraryElement.units) ...unit.libraryExports,
];
for (var exportedElement in exported) {
var exportedLibrary = exportedElement.exportedLibrary;
if (exportedLibrary != null) {
// Follow the exports down; as `publicLibrary` exports `libraryElement`,
Expand Down
2 changes: 1 addition & 1 deletion test/dartdoc_test_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ abstract class DartdocTestBase {

String get sdkConstraint => '>=3.6.0 <4.0.0';

List<String> get experiments => ['wildcard-variables'];
List<String> get experiments => ['enhanced-parts', 'wildcard-variables'];

bool get skipUnreachableSdkLibraries => true;

Expand Down
71 changes: 71 additions & 0 deletions test/packages_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:dartdoc/src/dartdoc_options.dart';
import 'package:dartdoc/src/model/class.dart';
import 'package:dartdoc/src/model/documentable.dart';
import 'package:dartdoc/src/model/kind.dart';
import 'package:dartdoc/src/package_config_provider.dart';
import 'package:dartdoc/src/package_meta.dart';
import 'package:dartdoc/src/special_elements.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'dartdoc_test_base.dart';
import 'src/test_descriptor_utils.dart' as d;
import 'src/utils.dart' as utils;

void main() {
defineReflectiveSuite(() {
defineReflectiveTests(PackagesTest);
});

// TODO(srawlins): Migrate to test_reflective_loader tests.

late MemoryResourceProvider resourceProvider;
late PackageMetaProvider packageMetaProvider;
late FakePackageConfigProvider packageConfigProvider;
Expand Down Expand Up @@ -103,6 +113,8 @@ int x;
projectPath, packageMetaProvider, packageConfigProvider);

expect(packageGraph.localPublicLibraries, hasLength(1));
var library = packageGraph.libraries.named('a');
expect(library.isDocumented, true);
});

test('has private libraries', () async {
Expand Down Expand Up @@ -489,3 +501,62 @@ int x;
});
});
}

@reflectiveTest
class PackagesTest extends DartdocTestBase {
@override
String get libraryName => 'lib';

void test_exportedElements() async {
var graph = await bootPackageFromFiles(
[
d.dir('lib', [
d.file('lib.dart', "export 'src/impl.dart';"),
d.dir('src', [
d.file('impl.dart', 'class C {}'),
]),
]),
],
);
var library = graph.libraries.named('lib');
expect(library.classes.single.name, 'C');
}

void test_exportedElements_indirectlyExported() async {
var graph = await bootPackageFromFiles(
[
d.dir('lib', [
d.file('lib.dart', "export 'src/impl.dart';"),
d.dir('src', [
d.file('impl.dart', "export 'impl2.dart';"),
d.file('impl2.dart', 'class C {}'),
]),
]),
],
);
var library = graph.libraries.named('lib');
expect(library.classes.single.name, 'C');
}

void test_exportedElements_fromPart() async {
var graph = await bootPackageFromFiles(
[
d.dir('lib', [
d.file('lib.dart', "part 'part.dart';"),
d.file('part.dart', '''
part of 'lib.dart';
export 'src/impl.dart';
'''),
d.dir('src', [
d.file('impl.dart', 'class C {}'),
]),
]),
],
);
var library = graph.libraries.named('lib');
expect(library.qualifiedName, 'lib');
expect(library.classes, isNotEmpty);
expect(library.classes.single,
isA<Class>().having((c) => c.name, 'name', 'C'));
}
}