Skip to content

Commit 6592c7c

Browse files
javier-godoypaodb
authored andcommitted
feat: add support for customizable demo URL resolution
1 parent 94fb94c commit 6592c7c

File tree

4 files changed

+100
-23
lines changed

4 files changed

+100
-23
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.flowingcode.vaadin.addons.demo;
2+
3+
import com.flowingcode.vaadin.addons.GithubBranch;
4+
import com.flowingcode.vaadin.addons.GithubLink;
5+
import java.util.Optional;
6+
7+
/**
8+
* Implementation of {@code SourceUrlResolver}.
9+
* <p>
10+
* If no {@code value} or {@code clazz} is specified, and the demo view is annotated with
11+
* {@link GithubLink}, then the source URL defaults to the location of the annotated class under
12+
* {@code src/test/java} and the branch is determined from the value of {@link GithubBranch} in the
13+
* demo view class (if the annotation is present) or the containing package of the demo view class.
14+
* If the source URL is defaulted and no {@code GithubBranch} annotation is present either in the
15+
* demo view class or its containing package, then the branch defaults to {@code master}.
16+
*
17+
* @author Javier Godoy / Flowing Code
18+
*/
19+
class DefaultSourceUrlResolver implements SourceUrlResolver {
20+
21+
@Override
22+
public Optional<String> resolveURL(TabbedDemo demo, Class<?> annotatedClass,
23+
DemoSource annotation) {
24+
String demoFile;
25+
String url = annotation.value();
26+
if (url.equals(DemoSource.GITHUB_SOURCE) || url.equals(DemoSource.DEFAULT_VALUE)) {
27+
String className;
28+
if (annotation.clazz() == DemoSource.class) {
29+
className = annotatedClass.getName().replace('.', '/');
30+
} else {
31+
className = annotation.clazz().getName().replace('.', '/');
32+
}
33+
demoFile = "src/test/java/" + className + ".java";
34+
} else if (url.startsWith("/src/test/")) {
35+
demoFile = url.substring(1);
36+
} else {
37+
demoFile = null;
38+
}
39+
40+
if (demoFile != null) {
41+
String branch = TabbedDemo.lookupGithubBranch(demo.getClass());
42+
return Optional.ofNullable(demo.getClass().getAnnotation(GithubLink.class))
43+
.map(githubLink -> String.format("%s/blob/%s/%s", githubLink.value(), branch, demoFile));
44+
} else {
45+
return Optional.empty();
46+
}
47+
}
48+
49+
}

src/main/java/com/flowingcode/vaadin/addons/demo/DemoSource.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636
* defaulted and no {@code GithubBranch} annotation is present either in the demo view class or its
3737
* containing package, then the branch defaults to {@code master}.
3838
*
39+
* This behavior can be globally overridden by configuring a {@link SourceUrlResolver}.
40+
*
3941
* @author Javier Godoy / Flowing Code
42+
* @see TabbedDemo#configureSourceUrlResolver(SourceUrlResolver)
4043
*/
4144
@Repeatable(DemoSources.class)
4245
@Retention(RetentionPolicy.RUNTIME)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.flowingcode.vaadin.addons.demo;
2+
3+
import java.util.Optional;
4+
5+
/**
6+
* Interface for resolving the source URL of a demo class.
7+
*
8+
* @author Javier Godoy / Flowing Code
9+
*/
10+
public interface SourceUrlResolver {
11+
12+
/**
13+
* Resolves the source URL for a given demo class and annotation.
14+
*
15+
* @param demo The {@link TabbedDemo} instance associated with the source.
16+
* @param annotatedClass The class that is annotated with {@link DemoSource}.
17+
* @param annotation The {@link DemoSource} annotation providing source metadata.
18+
* @return An {@link Optional} containing the resolved URL if available, otherwise an empty
19+
* {@link Optional}.
20+
*/
21+
Optional<String> resolveURL(TabbedDemo demo, Class<?> annotatedClass, DemoSource annotation);
22+
23+
}

src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
package com.flowingcode.vaadin.addons.demo;
2121

2222
import com.flowingcode.vaadin.addons.GithubBranch;
23-
import com.flowingcode.vaadin.addons.GithubLink;
2423
import com.vaadin.flow.component.AttachEvent;
2524
import com.vaadin.flow.component.Component;
2625
import com.vaadin.flow.component.ComponentEventListener;
@@ -45,6 +44,7 @@
4544
import java.util.Objects;
4645
import java.util.Optional;
4746
import java.util.stream.Stream;
47+
import lombok.NonNull;
4848
import org.slf4j.Logger;
4949
import org.slf4j.LoggerFactory;
5050

@@ -232,31 +232,33 @@ public void showRouterLayoutContent(HasElement content) {
232232
applyTheme(getElement(), getThemeName());
233233
}
234234

235-
private Optional<SourceCodeTab> createSourceCodeTab(Class<?> annotatedClass, DemoSource annotation) {
236-
String demoFile;
237-
String url = annotation.value();
238-
if (url.equals(DemoSource.GITHUB_SOURCE) || url.equals(DemoSource.DEFAULT_VALUE)) {
239-
String className;
240-
if (annotation.clazz() == DemoSource.class) {
241-
className = annotatedClass.getName().replace('.', '/');
242-
} else {
243-
className = annotation.clazz().getName().replace('.', '/');
244-
}
245-
demoFile = "src/test/java/" + className + ".java";
246-
} else if (url.startsWith("/src/test/")) {
247-
demoFile = url.substring(1);
248-
} else {
249-
demoFile = null;
235+
private static SourceUrlResolver resolver = null;
236+
237+
/**
238+
* Configures the {@code SourceUrlResolver} for resolving source URLs. This method can only be
239+
* called once; subsequent calls will result in an exception.
240+
*
241+
* @param resolver The {@code SourceUrlResolver} to be used. Must not be {@code null}.
242+
* @throws IllegalStateException if a resolver has already been set.
243+
* @throws NullPointerException if the provided {@code resolver} is {@code null}.
244+
*/
245+
public static void configureSourceUrlResolver(@NonNull SourceUrlResolver resolver) {
246+
if (TabbedDemo.resolver != null) {
247+
throw new IllegalStateException();
250248
}
249+
TabbedDemo.resolver = resolver;
250+
}
251251

252-
if (demoFile != null) {
253-
String branch = lookupGithubBranch(this.getClass());
254-
url = Optional.ofNullable(this.getClass().getAnnotation(GithubLink.class))
255-
.map(githubLink -> String.format("%s/blob/%s/%s", githubLink.value(),
256-
branch, demoFile))
257-
.orElse(null);
252+
private static SourceUrlResolver getResolver() {
253+
if (resolver == null) {
254+
resolver = new DefaultSourceUrlResolver();
258255
}
259-
256+
return resolver;
257+
}
258+
259+
private Optional<SourceCodeTab> createSourceCodeTab(Class<?> annotatedClass, DemoSource annotation) {
260+
String url = getResolver().resolveURL(this, annotatedClass, annotation).orElse(null);
261+
260262
if (url==null) {
261263
return Optional.empty();
262264
}

0 commit comments

Comments
 (0)