You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/09 08:13:20 UTC

[isis] branch master updated: ISIS-2473: adds support for java-doc link processing

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 38c8c05  ISIS-2473: adds support for java-doc link processing
38c8c05 is described below

commit 38c8c058b9052c2aa78f836ff606a3046481d4b2
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Dec 9 09:10:38 2020 +0100

    ISIS-2473: adds support for java-doc link processing
---
 .../org/apache/isis/tooling/cli/doclet/Doclet.java | 36 ++++++----
 .../isis/tooling/cli/doclet/DocletContext.java     | 65 ++++++++++++++++++
 .../apache/isis/tooling/cli/doclet/Doclets.java    | 40 +++--------
 .../cli/doclet/{Doclets.java => ToAsciiDoc.java}   | 77 ++++++++++++----------
 .../isis/tooling/cli/test/doclet/DocletTest.java   | 17 +++--
 .../cli/test/doclet/samples/SudoService.java       |  6 ++
 .../isis/tooling/javamodel/CompilationUnits.java   |  9 +--
 7 files changed, 165 insertions(+), 85 deletions(-)

diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java
index 55656e7..34b5ae5 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java
@@ -24,7 +24,7 @@ import java.util.Optional;
 import java.util.stream.Stream;
 
 import com.github.javaparser.StaticJavaParser;
-import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
 
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.tooling.javamodel.CompilationUnits;
@@ -42,7 +42,7 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class Doclet {
 
-    private final TypeDeclaration<?> td;
+    private final ClassOrInterfaceDeclaration td;
 
     public static Optional<Doclet> parse(final @NonNull File sourceFile) {
 
@@ -51,7 +51,7 @@ public class Doclet {
 
             return Stream.of(cu)
             .flatMap(CompilationUnits::streamPublicTypeDeclarations)
-            .filter(Doclets::isApacheIsisDoclet)
+            .filter(Doclets::hasIndexDirective)
             .map(Doclet::new)
             .findFirst();
 
@@ -61,8 +61,13 @@ public class Doclet {
         }
 
     }
+    
+    public String getName() {
+        return td.getNameAsString();
+    }
 
-    public String toAsciiDoc() {
+    public String toAsciiDoc(
+            final @NonNull DocletContext docletContext) {
         
         val doc = AsciiDocFactory.doc();
         
@@ -73,28 +78,34 @@ public class Doclet {
         val mds = TypeDeclarations.streamPublicMethodDeclarations(td)
                 .filter(Javadocs::presentAndNotHidden)
                 .collect(Can.toCan());
+        
+        val toAdocConverter = ToAsciiDoc.of(docletContext);
 
         // -- intro
         
         td.getJavadoc().ifPresent(javadoc->{
-            introBlock.setSource(Doclets.toAsciiDoc(javadoc));    
+            introBlock.setSource(toAdocConverter.javadoc(javadoc));    
         });
         
         // -- java content
         
         val java = new StringBuilder();
         
-        java.append(String.format("type %s {\n", td.getName().asString()));
+        java.append(String.format("%s %s {\n", 
+                getDeclarationKeyword(), 
+                td.getName().asString()));
         
         mds.forEach(md->{
 
-            java.append(String.format("\n  %s // <.>\n", Doclets.toNormalizedMethodDeclaration(md)));
+            java.append(String.format("\n  %s // <.>\n", 
+                    Doclets.toNormalizedMethodDeclaration(md)));
             
         });
 
         java.append("}\n");
         
-        javaSourceBlock.setSource(AsciiDocFactory.SourceFactory.java(java.toString(), td.getName().asString()));
+        javaSourceBlock.setSource(
+                AsciiDocFactory.SourceFactory.java(java.toString(), td.getName().asString()));
         
         // -- foot notes
         
@@ -107,7 +118,7 @@ public class Doclet {
             
                 footNotes.append(String.format("\n<.> `%s` %s\n",
                         Doclets.toNormalizedMethodDeclaration(md),
-                        Doclets.toAsciiDoc(javadoc)));
+                        toAdocConverter.javadoc(javadoc)));
                 
             });
             
@@ -125,10 +136,13 @@ public class Doclet {
         
     }
 
-
     // -- HELPER
 
-
+    private String getDeclarationKeyword() {
+        return td.isInterface()
+                ? "interface"
+                : "class";
+    }
 
 
 
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/DocletContext.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/DocletContext.java
new file mode 100644
index 0000000..7809488
--- /dev/null
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/DocletContext.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.tooling.cli.doclet;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.Builder;
+import lombok.NonNull;
+import lombok.Value;
+import lombok.val;
+
+@Value @Builder
+public class DocletContext {
+
+    private final @NonNull String indexXrefRoot;
+    
+    private final Map<String, Doclet> docletIndex = _Maps.newTreeMap();
+
+    public DocletContext add(final @NonNull Doclet doclet) {
+        val previousKey = docletIndex.put(doclet.getName(), doclet);
+        if(previousKey!=null) {
+            throw _Exceptions.unrecoverableFormatted(
+                    "doclet index entries must be unique (index key collision on %s)", 
+                    previousKey);
+        }
+        return this;
+    }
+    
+    public DocletContext add(final @NonNull File sourceFile) {
+        Doclet.parse(sourceFile)
+        .ifPresent(this::add);
+        return this;
+    }
+    
+    public Stream<Doclet> streamDoclets() {
+        return docletIndex.values().stream();
+    }
+
+    public Optional<Doclet> getDoclet(String key) {
+        return Optional.ofNullable(docletIndex.get(key));
+    }
+    
+}
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
index 9d7d947..15c0030 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
@@ -20,9 +20,6 @@ package org.apache.isis.tooling.cli.doclet;
 
 import com.github.javaparser.ast.body.MethodDeclaration;
 import com.github.javaparser.ast.body.TypeDeclaration;
-import com.github.javaparser.javadoc.Javadoc;
-import com.github.javaparser.javadoc.description.JavadocInlineTag;
-import com.github.javaparser.javadoc.description.JavadocSnippet;
 
 import org.apache.isis.tooling.javamodel.Javadocs;
 
@@ -31,7 +28,13 @@ import lombok.val;
 
 final class Doclets {
 
-    static boolean isApacheIsisDoclet(final @NonNull TypeDeclaration<?> td) {
+    /**
+     * Whether to include given {@link TypeDeclaration} with the index.
+     * <p>
+     * This is decided base on whether the type's java-doc has a
+     * {@literal @since} tag that contains the literal {@literal {@index}}. 
+     */
+    static boolean hasIndexDirective(final @NonNull TypeDeclaration<?> td) {
         return td.getJavadoc()
         .map(javadoc->{
         
@@ -44,35 +47,12 @@ final class Doclets {
         .orElse(false);
     }
     
+    /**
+     * Returns given {@link MethodDeclaration} as normal text, without formatting.
+     */
     static String toNormalizedMethodDeclaration(final @NonNull MethodDeclaration md) {
         return md.getDeclarationAsString(false, false, true).trim();
     }
     
-    static String toAsciiDoc(final @NonNull Javadoc javadoc) {
-        
-        val adoc = new StringBuilder();
-        
-        javadoc.getDescription().getElements()
-        .forEach(e->{
-            
-            if(e instanceof JavadocSnippet) {
-                adoc.append(normalizeHtmlTags(e.toText()));
-            } else if(e instanceof JavadocInlineTag) {
-                adoc.append(" _").append(((JavadocInlineTag) e).getContent().trim()).append("_ ");
-            } else {
-                adoc.append(e.toText());
-            }
-            
-        });
-        
-        return adoc.toString();
-    }
-    
-    // -- HELPER 
-    
-    private static String normalizeHtmlTags(final @NonNull String s) {
-        return s.replace("<p>", "\n").replace("</p>", "");
-    }
-    
     
 }
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/ToAsciiDoc.java
similarity index 58%
copy from tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
copy to tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/ToAsciiDoc.java
index 9d7d947..0e7f2a9 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/ToAsciiDoc.java
@@ -18,61 +18,72 @@
  */
 package org.apache.isis.tooling.cli.doclet;
 
-import com.github.javaparser.ast.body.MethodDeclaration;
-import com.github.javaparser.ast.body.TypeDeclaration;
 import com.github.javaparser.javadoc.Javadoc;
 import com.github.javaparser.javadoc.description.JavadocInlineTag;
 import com.github.javaparser.javadoc.description.JavadocSnippet;
 
-import org.apache.isis.tooling.javamodel.Javadocs;
-
 import lombok.NonNull;
+import lombok.Value;
 import lombok.val;
 
-final class Doclets {
-
-    static boolean isApacheIsisDoclet(final @NonNull TypeDeclaration<?> td) {
-        return td.getJavadoc()
-        .map(javadoc->{
-        
-            val toBeIncluded = Javadocs.streamTagContent(javadoc, "since") 
-            .anyMatch(since->since.toText().contains("{@index}"));
-            
-            return toBeIncluded;
-            
-        }) 
-        .orElse(false);
-    }
-    
-    static String toNormalizedMethodDeclaration(final @NonNull MethodDeclaration md) {
-        return md.getDeclarationAsString(false, false, true).trim();
-    }
-    
-    static String toAsciiDoc(final @NonNull Javadoc javadoc) {
-        
+@Value(staticConstructor = "of")
+class ToAsciiDoc {
+
+    private final DocletContext docletContext;
+
+    //TODO method java-doc needs further post processing when spanning multiple paragraphs
+    public String javadoc( 
+            final @NonNull Javadoc javadoc) {
+
         val adoc = new StringBuilder();
-        
+
         javadoc.getDescription().getElements()
         .forEach(e->{
-            
+
             if(e instanceof JavadocSnippet) {
                 adoc.append(normalizeHtmlTags(e.toText()));
             } else if(e instanceof JavadocInlineTag) {
-                adoc.append(" _").append(((JavadocInlineTag) e).getContent().trim()).append("_ ");
+                adoc.append(inlineTag((JavadocInlineTag) e));
             } else {
                 adoc.append(e.toText());
             }
-            
+
         });
-        
+
         return adoc.toString();
     }
+
+    public String inlineTag(
+            final @NonNull JavadocInlineTag inlineTag) {
+
+        val inlineContent = inlineTag.getContent().trim();
+
+        switch(inlineTag.getType()) {
+        case LINK:
+            val refDoclet = docletContext.getDoclet(inlineContent).orElse(null);
+            if(refDoclet!=null) {
+                return String.format(" %s ", xref(refDoclet));
+            }
+        default:
+            return String.format(" _%s_ ", inlineContent);
+        }
+    }
     
+    public String xref(
+            final @NonNull Doclet doclet) {
+        return String.format(" xref:%s:%s.adoc[%s] ", 
+                docletContext.getIndexXrefRoot(), 
+                doclet.getName(),
+                doclet.getName()); 
+    }
+
     // -- HELPER 
-    
+
+    /*
+     * try to convert HTML formatting directives to normal text  
+     */
     private static String normalizeHtmlTags(final @NonNull String s) {
         return s.replace("<p>", "\n").replace("</p>", "");
     }
-    
-    
+
 }
diff --git a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java
index 32077a3..5bf14b4 100644
--- a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java
@@ -19,11 +19,10 @@
 package org.apache.isis.tooling.cli.test.doclet;
 
 import java.io.File;
-import java.util.Optional;
 
 import org.junit.jupiter.api.Test;
 
-import org.apache.isis.tooling.cli.doclet.Doclet;
+import org.apache.isis.tooling.cli.doclet.DocletContext;
 import org.apache.isis.tooling.javamodel.AnalyzerConfigFactory;
 
 import lombok.val;
@@ -40,17 +39,21 @@ class DocletTest {
         val projDir = new File("./").getAbsoluteFile();
         val analyzerConfig = AnalyzerConfigFactory.mavenTest(projDir, Language.JAVA).main();
 
+        val docletContext = DocletContext.builder()
+                .indexXrefRoot("system:index")
+                .build();
+        
         analyzerConfig.getSources(JAVA)
         .stream()
-        .filter(source->source.toString().contains("UserService"))
+//        .filter(source->source.toString().contains("UserService"))
         .peek(source->System.out.println("parsing source: " + source))
-        .map(Doclet::parse)
-        .filter(Optional::isPresent)
-        .map(Optional::get)
+        .forEach(docletContext::add);
+        
+        docletContext.streamDoclets()
         .forEach(doclet->{
             
             System.out.println("--------------------------------------------------");
-            System.out.println(doclet.toAsciiDoc());
+            System.out.println(doclet.toAsciiDoc(docletContext));
             System.out.println("--------------------------------------------------");
 
         });
diff --git a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java
index 87f241c..35acc67 100644
--- a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java
@@ -18,6 +18,12 @@
  */
 package org.apache.isis.tooling.cli.test.doclet.samples;
 
+/**
+ * If {@link SudoService} has been used to temporarily override the user and/or roles, 
+ * then the {@link UserService} will report the overridden values.
+ *
+ * @since 2.0 {@index}
+ */
 public interface SudoService {
 
 }
diff --git a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java
index 9e1ad66..5851925 100644
--- a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java
@@ -24,7 +24,7 @@ import java.util.stream.Stream;
 
 import com.github.javaparser.StaticJavaParser;
 import com.github.javaparser.ast.CompilationUnit;
-import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
 
 import lombok.NonNull;
 import lombok.SneakyThrows;
@@ -43,14 +43,15 @@ public final class CompilationUnits {
         .orElse(false);
     }
     
-    public static <T> Stream<TypeDeclaration<?>> streamPublicTypeDeclarations(
+    public static <T> Stream<ClassOrInterfaceDeclaration> streamPublicTypeDeclarations(
             final @NonNull CompilationUnit compilationUnit) {
         
         val type = compilationUnit.getPrimaryType().orElse(null);
-        if(type==null) {
+        if(type==null
+                || !type.isClassOrInterfaceDeclaration()) {
             return Stream.empty();
         }
-        return Stream.of(type);
+        return Stream.of((ClassOrInterfaceDeclaration)type);
     }