Package Torello.Java

Class Lint


  • public class Lint
    extends java.lang.Object
    Lint - Documentation.

    The class can help control the line-length of the JavaDoc portion of '.java' source code files. It has a command line interface that will scroll the thee lines of Java Doc Comments, and ask if the linter has chosen appropriate places to break the lines up.

    It has a few rules about when to insert blank comment lines.

    Static (Functional) API: The methods in this class are all (100%) defined with the Java Key-Word / Key-Concept 'static'. Furthermore, there is no way to obtain an instance of this class, because there are no public (nor private) constructors. Java's Spring-Boot, MVC feature is *not* utilized because it flies directly in the face of the light-weight data-classes philosophy. This has many advantages over the rather ornate Component Annotations (@Component, @Service, @AutoWired, etc... 'Java Beans') syntax:

    • The methods here use the key-word 'static' which means (by implication) that there is no internal-state. Without any 'internal state' there is no need for constructors in the first place! (This is often the complaint by MVC Programmers).
    • A 'Static' (Functional-Programming) API expects to use fewer data-classes, and light-weight data-classes, making it easier to understand and to program.
    • The Vectorized HTML data-model allows more user-control over HTML parse, search, update & scrape. Also, memory management, memory leakage, and the Java Garbage Collector ought to be intelligible through the 'reuse' of the standard JDK class Vector for storing HTML Web-Page data.

    The power that object-oriented programming extends to a user is (mostly) limited to data-representation. Thinking of "Services" as "Objects" (Spring-MVC, 'Java Beans') is somewhat 'over-applying' the Object Oriented Programming Model. Like most classes in the Java-HTML JAR Library, this class backtracks to a more C-Styled Functional Programming Model (no Objects) - by re-using (quite profusely) the key-word static with all of its methods, and by sticking to Java's well-understood class Vector

    Static Fields: The methods in this class do not create any internal state that is maintained - however there are a few private & static fields defined. These fields are instantiated only once during the Class Loader phase (and only if this class shall be used), and serve as data 'lookup' fields (static constants). View this class' source-code in the link provided below to see internally used data.

    The fields in this class are all declared final and static and serve only as programming-constants. Their values could not changed. There are currently four public, static and final Regular-Expression Pattern's used for parsing, and two private String[] arrays - both used for parsing as well.



    • Field Detail

      • LONG_JD_COMMENT

        public static java.util.regex.Pattern LONG_JD_COMMENT
        Regular Expression for breaking up long lines of JavaDoc Comments
        Code:
        Exact Field Declaration Expression:
        1
        2
        public static Pattern LONG_JD_COMMENT = Pattern.compile
                ("^(     \\* [^\\n]{0,92})\\s([^\\n]+)\n");
        
      • LONG_JD_COMMENT_INNERCLASS

        public static final java.util.regex.Pattern LONG_JD_COMMENT_INNERCLASS
        Regular Expression for breaking up long lines of JavaDoc Comments
        Code:
        Exact Field Declaration Expression:
        1
        2
        public static final Pattern LONG_JD_COMMENT_INNERCLASS = Pattern.compile
                ("^(         \\* [^\\n]{0,88})\\s([^\\n]+)\n");
        
      • OPENING_HILITE_DIV

        public static final java.util.regex.Pattern OPENING_HILITE_DIV
        Regular Expression which matches lines that have JavaDoc Upgrade HiLite Dividers
        Code:
        Exact Field Declaration Expression:
        1
        2
        3
        public static final Pattern OPENING_HILITE_DIV = Pattern.compile
                ("<DIV\\s+CLASS=['\\\"](EXAMPLE|SNIP|LOC|SHELL|HTML|REGEX|SHELLBLOCK|COMPLETE)(-SCROLL)?['\\\"]\\w*>\\w*\\{",
                Pattern.CASE_INSENSITIVE);
        
      • CLOSING_HILITE_DIV

        public static final java.util.regex.Pattern CLOSING_HILITE_DIV
        Regular Expression which matches lines that have 'closing' HiLite Divider Elements.
        Code:
        Exact Field Declaration Expression:
        1
        2
        public static final Pattern CLOSING_HILITE_DIV = Pattern.compile
                ("\\}\\w*<\\/DIV>", Pattern.CASE_INSENSITIVE);
        
      • SAFE_ENDING

        public static final java.util.regex.Pattern SAFE_ENDING
        Long lines that don't require being queried by the user, because they only have text
        Code:
        Exact Field Declaration Expression:
        1
        2
        public static final Pattern SAFE_ENDING = Pattern.compile
                ("^.*?[\\w\\d\\s,\\-\\.]{20}$");
        
      • COMMENT_LINE_BEGINNING

        public static java.lang.String COMMENT_LINE_BEGINNING
        The first 7 characters of a line of text in JavaDoc Comments portions of source files.
        Code:
        Exact Field Declaration Expression:
        1
        public static String COMMENT_LINE_BEGINNING = "     * ";
        
    • Method Detail

      • main

        public static void main​(java.lang.String[] argv)
                         throws java.io.IOException
        Throws:
        java.io.IOException
        Code:
        Exact Method Body:
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
         if ((argv.length == 0) || (argv.length > 2))
         {
             System.out.println(man_page);
             System.exit(0);
         }
        
         if (argv.length == 1) lint(argv[0]);
         else
         {
             if (! argv[0].equals("INNERCLASS"))
             {
                 System.out.println(man_page);
                 System.exit(0);
             }
        
             LONG_JD_COMMENT = LONG_JD_COMMENT_INNERCLASS;
             COMMENT_LINE_BEGINNING = "    " + COMMENT_LINE_BEGINNING;
             lint(argv[1]);
         }
        
      • lint

        public static void lint​(java.lang.String inFileOrDir)
                         throws java.io.IOException
        Performs a 'LINT' on the input Java Source Code File.
        Parameters:
        inFileOrDir - This is any file or directory. If this is a directory, the entire directory will be scanned for '.java' source-files. If this is a file, then it will be the only file that is linted.
        Throws:
        java.io.FileNotFoundException - If this file or directory is not found.
        java.io.IOException
        Code:
        Exact Method Body:
          1
          2
          3
          4
          5
          6
          7
          8
          9
         10
         11
         12
         13
         14
         15
         16
         17
         18
         19
         20
         21
         22
         23
         24
         25
         26
         27
         28
         29
         30
         31
         32
         33
         34
         35
         36
         37
         38
         39
         40
         41
         42
         43
         44
         45
         46
         47
         48
         49
         50
         51
         52
         53
         54
         55
         56
         57
         58
         59
         60
         61
         62
         63
         64
         65
         66
         67
         68
         69
         70
         71
         72
         73
         74
         75
         76
         77
         78
         79
         80
         81
         82
         83
         84
         85
         86
         87
         88
         89
         90
         91
         92
         93
         94
         95
         96
         97
         98
         99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
         File            f = new File(inFileOrDir);
         Vector<String>  files;
        
         if (! f.exists()) throw new FileNotFoundException
             ("A file or directory named [" + inFileOrDir + "], was not found.");
        
         boolean lintingDirectory = true;
        
         if (f.isDirectory()) files = FileNode
             .createRoot(inFileOrDir)
             .loadTree(1, (File file, String name) -> name.endsWith(".java"), null)
             .flattenJustFiles(FileNode.RetTypeChoice.FULLPATH_VECTOR);
         else 
         {
             files = new Vector<>();
             files.add(inFileOrDir);
             lintingDirectory = false;
         }
        
         for (int fNum=0; fNum < files.size(); fNum++)
         {
             String file = files.elementAt(fNum);
        
             System.out.println(
                 "Linting File [" + C.BCYAN + (fNum+1) + " of " + files.size() + C.RESET + "]\n" +
                 "Visiting File: " + C.BYELLOW + file + C.RESET + "\n"
             );
        
             Vector<String>  javaFile        = FileRW.loadFileToVector(file, true);
             boolean         insideHiLiteDIV = false;
             int             linesAdded      = 0;
        
             for (int i=1; i < (javaFile.size()-1); i++)
             {
                 String  line                    = javaFile.elementAt(i);
                 String  prevLine                = javaFile.elementAt(i-1);
                 String  nextLine                = javaFile.elementAt(i+1);
        
                 String  lineTrimmed             = line.trim();
                 String  prevLineTrimmed         = prevLine.trim();
                 String  nextLineTrimmed         = nextLine.trim();
        
                 boolean lineIsComment           = line.startsWith(COMMENT_LINE_BEGINNING);
                 boolean nextLineIsComment       = nextLine.startsWith(COMMENT_LINE_BEGINNING);
                 boolean prevLineWasComment      = prevLine.startsWith(COMMENT_LINE_BEGINNING);
        
                 boolean lineIsTooLong           = line.length() > 100;
                 boolean prevLineWasBlankComment = prevLineTrimmed.equals("*");
                 boolean nextLineIsEndingComment = nextLineTrimmed.equals("*/");
                 boolean nthSeeTagInARow         = lineTrimmed.startsWith("* @see") && 
                                                     prevLineTrimmed.startsWith("* @see");
        
                 boolean hasOpeningHiLiteDIV     = lineIsComment && 
                                                     OPENING_HILITE_DIV.matcher(lineTrimmed).find();
        
                 boolean hasClosingHiLiteDIV     = lineIsComment && 
                                                     CLOSING_HILITE_DIV.matcher(lineTrimmed).find();
        
                 boolean mustBePreceededByBlankCommentLine =
                     lineIsComment &&
                     StrCmpr.startsWithXOR_CI(lineTrimmed, PREV_LINE_MUST_BE_STRS);
        
                 boolean appendToStartOfNextLineIsOK =
                     nextLineIsComment &&
                     (! StrCmpr.startsWithXOR_CI(nextLineTrimmed, CANNOT_PREPEND_TO_LINE_STRS)) &&
                     (! nextLineIsEndingComment);
        
                 // ************************************************************
                 // MAIN LOOP PART
                 // ************************************************************
        
                 if (hasOpeningHiLiteDIV)        insideHiLiteDIV = true;
                 else
                 {
                     if (hasClosingHiLiteDIV)    { insideHiLiteDIV = false; System.out.print(line); continue; }
                     if (insideHiLiteDIV)        { System.out.print(line); continue; }
                 } // tricky... shitty...
        
                 if (mustBePreceededByBlankCommentLine && (! prevLineWasBlankComment) && (! nthSeeTagInARow))
                 {
                     linesAdded++;
                     javaFile.add(i, COMMENT_LINE_BEGINNING + '\n');
                     System.out.print(C.BGREEN + COMMENT_LINE_BEGINNING + C.RESET + '\n');
                 }
                 else if (lineIsComment && lineIsTooLong)
                 {
                     System.out.print(C.BRED + line + C.RESET);
                     Matcher m = LONG_JD_COMMENT.matcher(line);
        
                     if (! m.find()) throw new IllegalStateException("MESSED UP, WTF?");
        
                     String shortenedLine    = StringParse.trimRight(m.group(1));
                     String restOfThisLine   = line.substring(m.end(1)).trim();
        
                     System.out.print(shortenedLine + '\n');
                     javaFile.setElementAt(shortenedLine + '\n', i);
        
                     if (! SAFE_ENDING.matcher(shortenedLine).find())
                         while (! Q.YN("Break OK?  (Currently on Line #" + i + " of " + javaFile.size() + ")"))
                         {
                             int pos = shortenedLine.lastIndexOf(' ');
                             if (pos == -1) System.exit(0);
        
                             restOfThisLine = shortenedLine.substring(pos + 1).trim() + ' ' + restOfThisLine;
                             shortenedLine = StringParse.trimRight(shortenedLine.substring(0, pos));
        
                             System.out.print(C.BRED + shortenedLine + C.RESET + '\n');
                             javaFile.setElementAt(shortenedLine + '\n', i);
                         }
        
                     if (restOfThisLine.length() == 0) continue;
        
                     if (appendToStartOfNextLineIsOK)
                     {
                         nextLine = COMMENT_LINE_BEGINNING + restOfThisLine + ' ' + 
                             nextLine.substring(COMMENT_LINE_BEGINNING.length());
                         javaFile.setElementAt(nextLine, i+1);
                     }
                     else
                     {
                         linesAdded++;
                         javaFile.add(i+1, COMMENT_LINE_BEGINNING + restOfThisLine + '\n');
                     }
                 }
                 else System.out.print(line);
             }
        
             System.out.println(
                 "Finished File:\t" + C.BYELLOW + file + C.RESET + '\n' +
                 "Added [" + C.BCYAN + StringParse.zeroPad(linesAdded) + C.RESET + "] new lines " +
                 "to  the file."
             );
        
             for (int count=5; count > 0; count--) 
                 Q.YN(
                     "Press Y/N " + C.BCYAN + StringParse.zeroPad(count) + C.RESET +
                     " more times..."
                 );
        
             String question = lintingDirectory
                 ? "Save and continue to next file?"
                 : "Save file?";
        
             if (! Q.YN(C.GREEN + question + C.RESET)) System.exit(0);
             FileRW.writeFile_NO_NEWLINE(javaFile, file);
             System.out.println("Wrote File:\t" + C.BYELLOW + file + C.RESET);
         }