All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.exadatum.xsuite.xmaven.bash.doc.DocBlockIterator Maven / Gradle / Ivy

Go to download

Bash Maven Plugin is used to generate documentation as well as to run unit test for bash scripts.

The newest version!
package com.exadatum.xsuite.xmaven.bash.doc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;

/*-
 * #%L
 * Bash Unit Test Plugin
 * %%
 * Copyright (C) 2016 - 2017 Exadatum Software Services Pvt. Ltd.
 * %%
 * Licensed 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.
 * #L%
 */

import org.apache.commons.lang3.StringUtils;

/**
 * Iterates over DocBlock.
 */
public class DocBlockIterator implements Iterator {

  /**
   * Line Separator.
   */
  private static final String LINE_SEPARATOR = System
      .getProperty("line.separator");

  /**
   * Maintain the index of Asterisk in Doc.
   */
  private static final int INDEX_OF_STAR = 1;

  /**
   * Lines of script.
   */
  private String[] lines;

  /**
   * Cursor.
   */
  private int cursor = -1;

  /**
   * Doc block lines.
   */
  private ArrayList docBlockLines = new ArrayList<>();

  /**
   * Description of Doc Block.
   */
  private ArrayList descriptionDocBlockLines = new ArrayList<>();

  /**
   * Target output.
   */
  private String target;

  /**
   * Parser block using parser and lexer generated using the grammar specified
   * using antlr4.
   */
  private DocBlockParser blockParser;

  /**
   * Flag for script description.
   */
  private boolean scriptDescriptionFound = false;

  /**
   * Constructor to initialize Lines and DocBlockParser.
   *
   * @param contents
   */
  public DocBlockIterator(final String contents) {
    this.lines = contents.split(LINE_SEPARATOR);
    blockParser = new DocBlockParser();
  }

  /**
   * Checks if there is any next valid documentation block is available or not.
   *
   * @return
   */
  @Override
  public boolean hasNext() {
    // Doc block consists of start tag, end tag and the element for which
    // the doc block has been written.
    boolean startTagFound = false;
    boolean endTagFound = false;

    if (cursor == -1) {
      // this is first call to hasNext.
      cursor = 0;
    }
    docBlockLines.clear();
    while (cursor < lines.length && !endTagFound) {

      // Start and End tag are expected to be on its own line.
      if (isValidStartTag()) {
        startTagFound = true;
        docBlockLines.add(DocBlockStructure.START.getKeyword().substring(1)
            .concat(LINE_SEPARATOR));
      } else if (isValidEndTag()) {
        if (!startTagFound) {
          throwInvalidBlockStructureException("Doc block end tag "
              + "found with no matching start tag at [%d]", cursor);
        }
        endTagFound = true;
        docBlockLines.add(DocBlockStructure.END.getKeyword().substring(1));
      } else if (isValidContinuationTag()) {
        if (!startTagFound) {
          throwInvalidBlockStructureException(
              "Doc block continuation tag found with no"
                  + " matching start tag at [%d]",
              cursor);
        }
        docBlockLines.add(
            lines[cursor].substring(INDEX_OF_STAR).concat(LINE_SEPARATOR));
      }
      cursor++;
    }

    if (startTagFound && !endTagFound) {
      throwInvalidBlockStructureException(
          "No end tag found in " + "the Doc block");
    }

    int tempCursor = cursor;
    while (tempCursor < lines.length) {
      String trimmedLine = lines[tempCursor].trim();
      if (!StringUtils.isBlank(trimmedLine)) {
        if (trimmedLine.startsWith("function ")) {
          target = trimmedLine.substring(trimmedLine.indexOf(" "),
              trimmedLine.indexOf("("));
          break;
        } else if (trimmedLine.indexOf("=") != -1) {
          target = trimmedLine;
          break;
        } else if (trimmedLine.startsWith("##") && !scriptDescriptionFound) {
          scriptDescriptionFound = true;
          target = "Description";
          break;
        } else {
          throwInvalidBlockStructureException(
              "Function or constant declaration shall follow document"
                  + " block. But found otherwise at [%d]",
              cursor);
        }
      }
      tempCursor++;
    }
    return endTagFound;
  }

  /**
   * Method for Invalid Block Structure Exception.
   *
   * @param message
   * @param args
   */
  private void throwInvalidBlockStructureException(final String message,
      final Object... args) {
    throw new InvalidDocBlockStructure(String.format(message, args));
  }

  /**
   * A valid start tag only contains {@link DocBlockStructure.START} and nothing
   * else.
   *
   * @return if the start tag is valid
   */
  private boolean isValidStartTag() {
    return isValidTag(DocBlockStructure.START, true);
  }

  /**
   * A valid end tag only contains {@link DocBlockStructure.END} and nothing
   * else.
   *
   * @return if the valid end tag
   */
  private boolean isValidEndTag() {
    return isValidTag(DocBlockStructure.END, true);
  }

  /**
   * A valid end tag only contains {@link DocBlockStructure.CONTINUATION} and
   * nothing else.
   *
   * @return if the continuation start tag is valid
   */
  private boolean isValidContinuationTag() {
    return isValidTag(DocBlockStructure.CONTINUATION, false);
  }

  /**
   * Validate if tag structure is correct.
   *
   * @return if the tag structure is valid
   */
  private boolean isValidTag(final DocBlockStructure tag,
      final boolean soloTag) {
    boolean isValid = false;
    String trimmedLine = lines[cursor].trim();
    // check if the line starts with the tag
    if (trimmedLine.startsWith(tag.getKeyword())) {
      // check if the line only contains the tag or is solo tag( start and
      // end tags are solo as they come on their own line)
      if (trimmedLine.length() == tag.getKeyword().length() || !soloTag) {
        isValid = true;
      } else {
        isValid = false;
        throwInvalidBlockStructureException(
            "Invalid [%1$s] tag at [%d]. [%1$s] tag shall always be"
                + " on its own line. " + "But some other characters found.",
            tag.name(), cursor);
      }
    }
    return isValid;
  }

  /**
   *
   * @return
   */
  @Override
  public DocBlock next() {
    if (cursor == -1) {
      // developer forgot to call hasNext. Blocks are read in hasNext
      // method.
      throw new IllegalStateException(
          "hasNext() method is not called." + " cursor is not open");
    }
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    if (!descriptionDocBlockLines.isEmpty()) {
      for (String docBlockLine : descriptionDocBlockLines) {
        try {
          baos.write(StringUtils.stripStart(docBlockLine, null)
              .getBytes(Charset.forName("UTF-8")));
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    } else if (!docBlockLines.isEmpty()) {
      for (String docBlockLine : docBlockLines) {
        try {
          baos.write(StringUtils.stripStart(docBlockLine, null)
              .getBytes(Charset.forName("UTF-8")));
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    }
    try {
      DocBlock docBlock = blockParser
          .parse(new ByteArrayInputStream(baos.toByteArray()));
      docBlock.setTarget(target);
      return docBlock;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy