Skip to content
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

feat: Left-hand Navigation: Group stub packages under parent #199

Merged
merged 8 commits into from
Sep 26, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.microsoft.build.BuilderUtil.populateUidValues;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.microsoft.lookup.ClassItemsLookup;
import com.microsoft.lookup.ClassLookup;
Expand Down Expand Up @@ -77,31 +78,40 @@ public boolean build() {
@VisibleForTesting
class Processor {
// table of contents
final TocFile tocFile = new TocFile(outputPath, projectName, disableChangelog);
private final TocFile tocFile = new TocFile(outputPath, projectName, disableChangelog);
// overview page
final MetadataFile projectMetadataFile = new MetadataFile(outputPath, "overview.yml");
private final MetadataFile projectMetadataFile = new MetadataFile(outputPath, "overview.yml");
// package summary pages
final List<MetadataFile> packageMetadataFiles = new ArrayList<>();
private final List<MetadataFile> packageMetadataFiles = new ArrayList<>();
// packages
final List<MetadataFileItem> packageItems = new ArrayList<>();
private final List<MetadataFileItem> packageItems = new ArrayList<>();
// class/enum/interface/etc. pages
final List<MetadataFile> classMetadataFiles = new ArrayList<>();
private final List<MetadataFile> classMetadataFiles = new ArrayList<>();

private final List<PackageElement> allPackages =
elementUtil.extractPackageElements(environment.getIncludedElements());

@VisibleForTesting
void process() {
ImmutableListMultimap<PackageGroup, PackageElement> organizedPackages =
ImmutableListMultimap<PackageGroup, PackageElement> organizedPackagesWithoutStubs =
packageLookup.organize(
elementUtil.extractPackageElements(environment.getIncludedElements()));
allPackages.stream()
.filter(pkg -> !packageLookup.isApiVersionStubPackage(pkg))
.collect(Collectors.toList()));

for (PackageElement element : organizedPackages.get(PackageGroup.VISIBLE)) {
for (PackageElement element : organizedPackagesWithoutStubs.get(PackageGroup.VISIBLE)) {
tocFile.addTocItem(buildPackage(element));
}

TocItem older = new TocItem(OLDER_AND_PRERELEASE, OLDER_AND_PRERELEASE, null);
for (PackageElement element : organizedPackages.get(PackageGroup.OLDER_AND_PRERELEASE)) {
older.getItems().add(buildPackage(element));
ImmutableList<PackageElement> olderPackages =
organizedPackagesWithoutStubs.get(PackageGroup.OLDER_AND_PRERELEASE);
if (!olderPackages.isEmpty()) {
TocItem older = new TocItem(OLDER_AND_PRERELEASE, OLDER_AND_PRERELEASE, null);
for (PackageElement element : olderPackages) {
older.getItems().add(buildPackage(element));
}
tocFile.addTocItem(older);
}
tocFile.addTocItem(older);

for (MetadataFile packageFile : packageMetadataFiles) {
packageItems.addAll(packageFile.getItems());
Expand Down Expand Up @@ -138,6 +148,11 @@ private TocItem buildPackage(PackageElement element) {
classBuilder.buildFilesForInnerClasses(element, typeMap, classMetadataFiles);
packageTocItem.getItems().addAll(joinTocTypeItems(typeMap));

// build stubs
packageLookup
.findStubPackages(element, allPackages)
.forEach((PackageElement stub) -> packageTocItem.getItems().add(buildPackage(stub)));

return packageTocItem;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
import com.google.docfx.doclet.ApiVersion;
import com.microsoft.lookup.model.ExtendedMetadataFileItem;
import com.microsoft.model.Status;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.lang.model.element.PackageElement;
import jdk.javadoc.doclet.DocletEnvironment;

Expand Down Expand Up @@ -67,15 +69,45 @@ public String extractJavaType(PackageElement element) {
return null;
}

/**
* @return true, if the package ends with 'stub' and its parent package is an API version
*/
public boolean isApiVersionStubPackage(PackageElement pkg) {
return isApiVersionStubPackageName(String.valueOf(pkg.getQualifiedName()));
}

/**
* @return true, if the package ends with 'stub' and its parent package is an API version
*/
@VisibleForTesting
boolean isApiVersionStubPackageName(String name) {
List<String> packagePath = Arrays.asList(name.split("\\."));
int stubIndex = packagePath.indexOf("stub");
if (stubIndex < 1) {
return false;
}
return ApiVersion.parse(packagePath.get(stubIndex - 1)).isPresent();
}

public List<PackageElement> findStubPackages(
PackageElement pkg, Collection<PackageElement> packages) {
String expectedStubPackageBase = pkg.getQualifiedName() + ".stub";
return packages.stream()
.filter(p -> String.valueOf(p.getQualifiedName()).startsWith(expectedStubPackageBase))
.sorted()
.collect(Collectors.toList());
}

/** Compare PackageElements by their parsed ApiVersion */
private final Comparator<PackageElement> byComparingApiVersion =
Comparator.comparing(pkg -> extractApiVersion(pkg).orElse(ApiVersion.NONE));

public Optional<ApiVersion> extractApiVersion(PackageElement pkg) {
String name = String.valueOf(pkg.getQualifiedName());
int lastPackageIndex = name.lastIndexOf('.');
String leafPackage = name.substring(lastPackageIndex + 1);
return ApiVersion.parse(leafPackage);
return extractApiVersion(String.valueOf(pkg.getQualifiedName()));
}

public Optional<ApiVersion> extractApiVersion(String name) {
return ApiVersion.parse(getLeafPackage(name));
}

public enum PackageGroup {
Expand Down Expand Up @@ -132,17 +164,14 @@ Multimap<String, PackageElement> groupVersions(List<PackageElement> packages) {
packages,
(pkg) -> {
String name = String.valueOf(pkg.getQualifiedName());
int lastPackageIndex = name.lastIndexOf('.');
String leafPackage = name.substring(lastPackageIndex + 1);
// For package a.b.c.d, the value of leafPackage is 'd'.

boolean packageIsApiVersion = ApiVersion.parse(leafPackage).isPresent();
// Group all API version packages into a single .v# group
boolean packageIsApiVersion = ApiVersion.parse(getLeafPackage(name)).isPresent();
if (packageIsApiVersion) {
String packageWithoutVersion = name.substring(0, lastPackageIndex);
// For package a.b.c.v1, the value of packageWithoutVersion is a.b.c
return packageWithoutVersion + ".v#"; // Use "v#" package to group all versions
return withoutLeafPackage(name) + ".v#"; // withoutLeafPackage("a.b.c.v1") --> "a.b.c"
}
// Using 'name' ensures this package is placed in a group of size 1.

// When not an API version package, use 'name' to ensure a unique group of size 1.
return name;
});
}
Expand Down Expand Up @@ -174,4 +203,16 @@ PackageElement getRecommended(Collection<PackageElement> packages) {
ApiVersion recommended = ApiVersion.getRecommended(versions.keySet());
return versions.get(recommended);
}

/** withoutLeafPackage("a.b.c.d") --> "a.b.c" */
private String withoutLeafPackage(String name) {
int lastPackageIndex = name.lastIndexOf('.');
return name.substring(0, lastPackageIndex);
}

/** getLeafPackage("a.b.c.d") --> "d" */
private String getLeafPackage(String name) {
int lastPackageIndex = name.lastIndexOf('.');
return name.substring(lastPackageIndex + 1);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.microsoft.doclet;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

Expand Down Expand Up @@ -105,20 +104,6 @@ public void assertSameFileNames(List<Path> expected, List<Path> generated) {
List<String> generatedFilenames =
generated.stream().map(Path::getFileName).map(Path::toString).collect(Collectors.toList());

assertWithMessage("Expected files were not generated.")
.that(
expectedFilenames.stream()
.filter(file -> !generatedFilenames.contains(file))
.collect(Collectors.toList()))
.isEmpty();

assertWithMessage("Files were generated that should not have been.")
.that(
generatedFilenames.stream()
.filter(file -> !expectedFilenames.contains(file))
.collect(Collectors.toList()))
.isEmpty();

assertThat(expected.size()).isEqualTo(generated.size());
assertThat(generatedFilenames).containsExactlyElementsIn(expectedFilenames);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,58 @@ public void testOrganize_WithoutReleasePackage() {
.containsExactly("com.microsoft.samples.google.v1beta");
}

@Test
public void testFindStubPackage() {
ImmutableList<PackageElement> packages =
ImmutableList.of(
elements.getPackageElement("com.microsoft.samples.google.v1"),
elements.getPackageElement("com.microsoft.samples.google.v1.stub"),
elements.getPackageElement("com.microsoft.samples.google.v1beta"),
elements.getPackageElement("com.microsoft.samples.google"));

List<PackageElement> foundStubPackages =
packageLookup.findStubPackages(
elements.getPackageElement("com.microsoft.samples.google.v1"), packages);
assertThat(foundStubPackages).isNotEmpty();
assertThat(foundStubPackages).hasSize(1);
assertThat(toPackageName(foundStubPackages.get(0)))
.isEqualTo("com.microsoft.samples.google.v1.stub");

List<PackageElement> notFoundStubPackageOfStubPackage =
packageLookup.findStubPackages(
elements.getPackageElement("com.microsoft.samples.google.v1.stub"), packages);
assertThat(notFoundStubPackageOfStubPackage).isEmpty();

List<PackageElement> notFoundStubPackage =
packageLookup.findStubPackages(
elements.getPackageElement("com.microsoft.samples.google"), packages);
assertThat(notFoundStubPackage).isEmpty();
}

@Test
public void testIsApiStubPackage() {
assertThat(
packageLookup.isApiVersionStubPackage(
elements.getPackageElement("com.microsoft.samples.google.v1")))
.isFalse();
assertThat(
packageLookup.isApiVersionStubPackage(
elements.getPackageElement("com.microsoft.samples.google.v1.stub")))
.isTrue();
assertThat(
packageLookup.isApiVersionStubPackageName("com.microsoft.samples.google.v1.stub.child"))
.isTrue();

assertThat(packageLookup.isApiVersionStubPackageName("a")).isFalse();
// False due to not being an API version package, even though it ends in .stub
assertThat(packageLookup.isApiVersionStubPackageName("a.stub")).isFalse();
}

private List<String> toPackageNames(List<PackageElement> packages) {
return packages.stream()
.map(pkg -> String.valueOf(pkg.getQualifiedName()))
.collect(Collectors.toList());
return packages.stream().map(this::toPackageName).collect(Collectors.toList());
}

private String toPackageName(PackageElement pkg) {
return String.valueOf(pkg.getQualifiedName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
* @deprecated Use {@link AgreementMetaData} instead.
*/
@Deprecated
public class AgreementDetailsCollectionOperations extends BasePartnerComponentString
implements IAgreementDetailsCollection {
/**
Expand All @@ -25,6 +26,7 @@ public AgreementDetailsCollectionOperations(IPartner rootPartnerOperations) {
* @return A list of agreement details.
* @deprecated Some text
*/
@Deprecated
public ResourceCollection<AgreementMetaData> get() {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public void setTemplateId(String value) {
*
* @deprecated
*/
@Deprecated
@JsonProperty("agreementLink")
private String agreementLink;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*
* @deprecated This one is deprecated :(
*/
@Deprecated
public interface IAgreementDetailsCollection {
/**
* Retrieves all current agreement metadata.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
* }</pre>
*/
@Generated("by gapic-generator-java")
@SuppressWarnings("unchecked")
public class ProductSearchSettings extends ClientSettings<ProductSearchSettings> {

/** Returns the object with the settings used for calls to createProductSet. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
*/
@BetaApi
@Generated("by gapic-generator-java")
@SuppressWarnings("unchecked")
public class SpeechSettings extends ClientSettings<SpeechSettings> {

/** Returns the object with the settings used for calls to recognize. */
Expand Down
Loading