Skip to content

Commit

Permalink
Adds a way to customise how component descriptions are set; also some…
Browse files Browse the repository at this point in the history
… tidy-up/renaming.
  • Loading branch information
simonbrowndotje committed Sep 17, 2024
1 parent becf089 commit 1e2b19c
Show file tree
Hide file tree
Showing 22 changed files with 410 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.structurizr.component;

import com.structurizr.component.description.DefaultDescriptionStrategy;
import com.structurizr.component.description.DescriptionStrategy;
import com.structurizr.component.filter.TypeFilter;
import com.structurizr.component.matcher.TypeMatcher;
import com.structurizr.component.naming.NamingStrategy;
Expand Down Expand Up @@ -27,14 +29,16 @@ public final class ComponentFinderStrategy {
private final TypeFilter typeFilter;
private final SupportingTypesStrategy supportingTypesStrategy;
private final NamingStrategy namingStrategy;
private final DescriptionStrategy descriptionStrategy;
private final ComponentVisitor componentVisitor;

ComponentFinderStrategy(String technology, TypeMatcher typeMatcher, TypeFilter typeFilter, SupportingTypesStrategy supportingTypesStrategy, NamingStrategy namingStrategy, ComponentVisitor componentVisitor) {
ComponentFinderStrategy(String technology, TypeMatcher typeMatcher, TypeFilter typeFilter, SupportingTypesStrategy supportingTypesStrategy, NamingStrategy namingStrategy, DescriptionStrategy descriptionStrategy, ComponentVisitor componentVisitor) {
this.technology = technology;
this.typeMatcher = typeMatcher;
this.typeFilter = typeFilter;
this.supportingTypesStrategy = supportingTypesStrategy;
this.namingStrategy = namingStrategy;
this.descriptionStrategy = descriptionStrategy;
this.componentVisitor = componentVisitor;
}

Expand All @@ -45,7 +49,7 @@ Set<DiscoveredComponent> findComponents(TypeRepository typeRepository) {
for (Type type : types) {
if (typeMatcher.matches(type) && typeFilter.accept(type)) {
DiscoveredComponent component = new DiscoveredComponent(namingStrategy.nameOf(type), type);
component.setDescription(type.getDescription());
component.setDescription(descriptionStrategy.descriptionOf(type));
component.setTechnology(this.technology);
component.setComponentFinderStrategy(this);
components.add(component);
Expand All @@ -71,6 +75,7 @@ public String toString() {
", typeFilter=" + typeFilter +
", supportingTypesStrategy=" + supportingTypesStrategy +
", namingStrategy=" + namingStrategy +
", descriptionStrategy=" + descriptionStrategy +
", componentVisitor=" + componentVisitor +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.structurizr.component;

import com.structurizr.component.description.DefaultDescriptionStrategy;
import com.structurizr.component.description.DescriptionStrategy;
import com.structurizr.component.filter.DefaultTypeFilter;
import com.structurizr.component.filter.TypeFilter;
import com.structurizr.component.matcher.TypeMatcher;
Expand All @@ -21,6 +23,7 @@ public final class ComponentFinderStrategyBuilder {
private TypeFilter typeFilter;
private SupportingTypesStrategy supportingTypesStrategy;
private NamingStrategy namingStrategy;
private DescriptionStrategy descriptionStrategy;
private ComponentVisitor componentVisitor;

public ComponentFinderStrategyBuilder() {
Expand Down Expand Up @@ -68,7 +71,7 @@ public ComponentFinderStrategyBuilder supportedBy(SupportingTypesStrategy suppor
return this;
}

public ComponentFinderStrategyBuilder namedBy(NamingStrategy namingStrategy) {
public ComponentFinderStrategyBuilder withName(NamingStrategy namingStrategy) {
if (namingStrategy == null) {
throw new IllegalArgumentException("A naming strategy must be provided");
}
Expand All @@ -82,7 +85,21 @@ public ComponentFinderStrategyBuilder namedBy(NamingStrategy namingStrategy) {
return this;
}

public ComponentFinderStrategyBuilder asTechnology(String technology) {
public ComponentFinderStrategyBuilder withDescription(DescriptionStrategy descriptionStrategy) {
if (descriptionStrategy == null) {
throw new IllegalArgumentException("A description strategy must be provided");
}

if (this.descriptionStrategy != null) {
throw new IllegalArgumentException("A description strategy has already been configured");
}

this.descriptionStrategy = descriptionStrategy;

return this;
}

public ComponentFinderStrategyBuilder forTechnology(String technology) {
if (StringUtils.isNullOrEmpty(technology)) {
throw new IllegalArgumentException("A technology must be provided");
}
Expand Down Expand Up @@ -127,11 +144,15 @@ public ComponentFinderStrategy build() {
namingStrategy = new DefaultNamingStrategy();
}

if (descriptionStrategy == null) {
descriptionStrategy = new DefaultDescriptionStrategy();
}

if (componentVisitor == null) {
componentVisitor = new DefaultComponentVisitor();
}

return new ComponentFinderStrategy(technology, typeMatcher, typeFilter, supportingTypesStrategy, namingStrategy, componentVisitor);
return new ComponentFinderStrategy(technology, typeMatcher, typeFilter, supportingTypesStrategy, namingStrategy, descriptionStrategy, componentVisitor);
}

@Override
Expand All @@ -142,6 +163,7 @@ public String toString() {
", typeFilter=" + typeFilter +
", supportingTypesStrategy=" + supportingTypesStrategy +
", namingStrategy=" + namingStrategy +
", descriptionStrategy=" + descriptionStrategy +
", componentVisitor=" + componentVisitor +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.structurizr.component.description;

import com.structurizr.component.Type;
import com.structurizr.component.naming.NamingStrategy;

/**
* Uses the type description as-is.
*/
public class DefaultDescriptionStrategy implements DescriptionStrategy {

@Override
public String descriptionOf(Type type) {
return type.getDescription();
}

@Override
public String toString() {
return "DefaultDescriptionStrategy{}";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.structurizr.component.description;

import com.structurizr.component.Type;

public interface DescriptionStrategy {

String descriptionOf(Type type);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.structurizr.component.description;

import com.structurizr.component.Type;
import com.structurizr.util.StringUtils;

/**
* Uses the first sentence of the type description, or the description as-is if there are no sentences.
*/
public class FirstSentenceDescriptionStrategy implements DescriptionStrategy {

@Override
public String descriptionOf(Type type) {
String description = type.getDescription();

int index = description.indexOf('.');
if (index == -1) {
return description;
} else {
return description.substring(0, index+1);
}
}

@Override
public String toString() {
return "FirstSentenceDescriptionStrategy{}";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.structurizr.component.description;

import com.structurizr.component.Type;
import com.structurizr.util.StringUtils;

/**
* Truncates the type description to the max length, appending "..." when truncated.
*/
public class TruncatedDescriptionStrategy implements DescriptionStrategy {

private final int maxLength;

public TruncatedDescriptionStrategy(int maxLength) {
if (maxLength < 1) {
throw new IllegalArgumentException("Max length must be greater than 0");
}

this.maxLength = maxLength;
}

@Override
public String descriptionOf(Type type) {
String description = type.getDescription();

if (StringUtils.isNullOrEmpty(description)) {
return description;
}

if (description.length() > maxLength) {
return description.substring(0, maxLength) + "...";
} else {
return description;
}
}

@Override
public String toString() {
return "TruncatedDescriptionStrategy{" +
"maxLength=" + maxLength +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@
/**
* Uses the simple/short name of the type (i.e. without the package name).
*/
public class SimpleNamingStrategy implements NamingStrategy {
public class TypeNamingStrategy implements NamingStrategy {

public String nameOf(Type type) {
return type.getName();
}

}
@Override
public String toString() {
return "TypeNamingStrategy{}";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,7 @@
*/
class JavadocCommentFilter {

private final Integer maxCommentLength;

JavadocCommentFilter(Integer maxCommentLength) {
if (maxCommentLength != null && maxCommentLength < 1) {
throw new IllegalArgumentException("Maximum comment length must be greater than 0.");
}

this.maxCommentLength = maxCommentLength;
}

String filterAndTruncate(String s) {
String filter(String s) {
if (s == null) {
return null;
}
Expand All @@ -25,11 +15,7 @@ String filterAndTruncate(String s) {
s = s.replaceAll("\\{@link (\\S*)\\}", "$1");
s = s.replaceAll("\\{@link (\\S*) (.*?)\\}", "$2");

if (maxCommentLength != null && s.length() > maxCommentLength) {
return s.substring(0, maxCommentLength-3) + "...";
} else {
return s;
}
return s;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,11 @@ public final class SourceDirectoryTypeProvider implements TypeProvider {

private static final Log log = LogFactory.getLog(SourceDirectoryTypeProvider.class);
private static final String JAVA_FILE_EXTENSION = ".java";
private static final int DEFAULT_DESCRIPTION_LENGTH = 60;

private final File directory;
private final int maximumDescriptionLength;
private final Set<Type> types = new LinkedHashSet<>();

public SourceDirectoryTypeProvider(File directory) {
this(directory, DEFAULT_DESCRIPTION_LENGTH);
}

public SourceDirectoryTypeProvider(File directory, int maximumDescriptionLength) {
if (directory == null) {
throw new IllegalArgumentException("A directory must be supplied");
}
Expand All @@ -47,24 +41,23 @@ public SourceDirectoryTypeProvider(File directory, int maximumDescriptionLength)
}

this.directory = directory;
this.maximumDescriptionLength = maximumDescriptionLength;
StaticJavaParser.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21);
}

@Override
public Set<Type> getTypes() {
parse(directory, maximumDescriptionLength);
parse(directory);

return new LinkedHashSet<>(types);
}

private void parse(File path, int maximumDescriptionLength) {
private void parse(File path) {
if (path.isDirectory()) {
File[] files = path.listFiles();
if (files != null) {
for (File file : files) {
try {
parse(file, maximumDescriptionLength);
parse(file);
} catch (Exception e) {
log.warn("Error parsing " + file.getAbsolutePath(), e);
}
Expand All @@ -85,7 +78,7 @@ public void visit(ClassOrInterfaceDeclaration n, Object arg) {
JavadocComment javadocComment = (JavadocComment) n.getComment().get();
String description = javadocComment.parse().getDescription().toText();

type.setDescription(new JavadocCommentFilter(maximumDescriptionLength).filterAndTruncate(description));
type.setDescription(new JavadocCommentFilter().filter(description));
}
types.add(type);
}
Expand All @@ -107,7 +100,7 @@ public void visit(PackageDeclaration n, Object arg) {
JavadocComment javadocComment = (JavadocComment)rootNode.getComment().get();
String description = javadocComment.parse().getDescription().toText();

type.setDescription(new JavadocCommentFilter(maximumDescriptionLength).filterAndTruncate(description));
type.setDescription(new JavadocCommentFilter().filter(description));
}

types.add(type);
Expand Down
Loading

0 comments on commit 1e2b19c

Please sign in to comment.