<commit_before>/*
 * This file is part of the Weborganic XMLDoclet library.
 *
 * For licensing information please see the file license.txt included in the release.
 * A copy of this licence can also be found at
 *   http://www.opensource.org/licenses/artistic-license-2.0.php
 */
package org.weborganic.xmldoclet;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.AnnotationDesc.ElementValuePair;
import com.sun.javadoc.AnnotationTypeElementDoc;
import com.sun.javadoc.AnnotationValue;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.LanguageVersion;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.SeeTag;
import com.sun.javadoc.Tag;
import com.sun.javadoc.ThrowsTag;
import com.sun.tools.doclets.Taglet;

/**
 * The Doclet implementation to use with javadoc.
 *
 * <p>A Doclet to be used with JavaDoc which will output XML with all of the information from the JavaDoc.
 *
 * @author <NAME>
 *
 * @version 7 May 2012
 */
public final class XMLDoclet {

  /**
   * The date format matching ISO 8601, easier to parse with XSLT.
   */
  private static final String ISO_8601 = "yyyy-MM-dd'T'HH:mm:ss";

  // Methods required by doclet specifications ====================================================

  /**
   * The method used by this method invocation.
   */
  private static Options options = null;

  /**
   * Processes the JavaDoc documentation.
   *
   * <p>This method is required for all doclets.
   *
   * @see com.sun.javadoc.Doclet#start(RootDoc)
   *
   * @param root The root of the documentation tree.
   *
   * @return <code>true</code> if processing was successful.
   */
  public static boolean start(RootDoc root) {
    // Create the root node.
    List<XMLNode> nodes = toXMLNodes(root);

    // Save the output XML
    save(nodes);

    return true;
  }

  /**
   * Returns the version of the Java Programming Language supported by this Doclet.
   *
   * <p>This Doclet supports Java 5.
   *
   * @see com.sun.javadoc.Doclet#languageVersion()
   *
   * @return {@value LanguageVersion#JAVA_1_5}
   */
  public static LanguageVersion languageVersion() {
    return LanguageVersion.JAVA_1_5;
  }

  /**
   * Returns the number of arguments required for the given option.
   *
   * <p>This method calls {@link Options#getLength(String)}.
   *
   * @see com.sun.javadoc.Doclet#optionLength(String)
   * @see Options#getLength(String)
   *
   * @param option The name of the option.
   *
   * @return The number of arguments for that option.
   */
  public static int optionLength(String option) {
    return Options.getLength(option);
  }

  /**
   * Check that options have the correct arguments.
   *
   * <p>This method is not required, but is recommended, as every option will be considered valid
   * if this method is not present. It will default gracefully (to true) if absent.
   *
   * <p>Printing option related error messages (using the provided DocErrorReporter) is the
   * responsibility of this method.
   *
   * @see com.sun.javadoc.Doclet#validOptions(String[][], DocErrorReporter)
   *
   * @param options The two dimensional array of options.
   * @param reporter The error reporter.
   *
   * @return <code>true</code> if the options are valid.
   */
  public static boolean validOptions(String o[][], DocErrorReporter reporter) {
    options = Options.toOptions(o, reporter);
    // OK if we could set up the options.
    return options != null;
  }

  // Methods specific to this doclet implementation ===============================================

  /**
   * Save the given array of nodes.
   *
   * Will either save the files individually, or as a single file depending on the existence of the "-multiple" flag.
   *
   * @param nodes The array of nodes to be saved.
   */
  private static void save(List<XMLNode> nodes) {
    // Add admin node
    XMLNode meta = new XMLNode("meta");
    DateFormat df = new SimpleDateFormat(ISO_8601);
    meta.attribute("created", df.format(new Date()));

    // Multiple files
    if (options.useMultipleFiles()) {
      for (XMLNode node : nodes) {
        File dir = options.getDirectory();
        String name = node.getAttribute("name");
        if (options.useSubFolders()) {
          name = name.replace('.', '/');
          int x = name.lastIndexOf('/');
          if (x >= 0) {
            dir = new File(dir, name.substring(0,x));
            dir.mkdirs();
            name = name.substring(x+1);
          }
        }
        XMLNode root = new XMLNode("root");
        root.attribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
        root.child(meta);
        root.child(node);
        String fileName = name + ".xml";
        root.save(dir, fileName, options.getEncoding(), "");
      }
      // Index
      XMLNode root = new XMLNode("root");
      root.child(meta);
      root.attribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
      for (XMLNode node : nodes) {
        String name = node.getAttribute("name");
        if (options.useSubFolders()) name = name.replace('.', '/');
        XMLNode ref = new XMLNode(node.getName());
        ref.attribute("xlink:type", "simple");
        ref.attribute("xlink:href", name + ".xml");
        root.child(ref);
      }
      String fileName = "index.xml";
      root.save(options.getDirectory(), fileName, options.getEncoding(), "");

    // Single file
    } else {
      // Wrap the XML
      XMLNode root = new XMLNode("root");
      root.child(meta);
      for (XMLNode node : nodes) {
        root.child(node);
      }
      root.save(options.getDirectory(), options.getFilename(), options.getEncoding(), "");
    }

  }

  /**
   * Returns the XML nodes for all the selected classes in the specified RootDoc.
   *
   * @param root The RootDoc from which the XML should be built.
   * @return The list of XML nodes which represents the RootDoc.
   */
  private static List<XMLNode> toXMLNodes(RootDoc root) {
    List<XMLNode> nodes = new ArrayList<XMLNode>();

    // Iterate over the classes
    for (ClassDoc doc : root.classes()) {
      if (options.filter(doc)) {
        nodes.add(toClassNode(doc));
      }
    }

    // Iterate over packages
    if (!options.hasFilter()) {<commit_msg>Added again xlink namespace for references (@see tags)<commit_after>/*
 * This file is part of the Weborganic XMLDoclet library.
 *
 * For licensing information please see the file license.txt included in the release.
 * A copy of this licence can also be found at
 *   http://www.opensource.org/licenses/artistic-license-2.0.php
 */
package org.weborganic.xmldoclet;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.AnnotationDesc.ElementValuePair;
import com.sun.javadoc.AnnotationTypeElementDoc;
import com.sun.javadoc.AnnotationValue;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.LanguageVersion;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.SeeTag;
import com.sun.javadoc.Tag;
import com.sun.javadoc.ThrowsTag;
import com.sun.tools.doclets.Taglet;

/**
 * The Doclet implementation to use with javadoc.
 *
 * <p>A Doclet to be used with JavaDoc which will output XML with all of the information from the JavaDoc.
 *
 * @author <NAME>
 *
 * @version 7 May 2012
 */
public final class XMLDoclet {

  /**
   * The date format matching ISO 8601, easier to parse with XSLT.
   */
  private static final String ISO_8601 = "yyyy-MM-dd'T'HH:mm:ss";

  // Methods required by doclet specifications ====================================================

  /**
   * The method used by this method invocation.
   */
  private static Options options = null;

  /**
   * Processes the JavaDoc documentation.
   *
   * <p>This method is required for all doclets.
   *
   * @see com.sun.javadoc.Doclet#start(RootDoc)
   *
   * @param root The root of the documentation tree.
   *
   * @return <code>true</code> if processing was successful.
   */
  public static boolean start(RootDoc root) {
    // Create the root node.
    List<XMLNode> nodes = toXMLNodes(root);

    // Save the output XML
    save(nodes);

    return true;
  }

  /**
   * Returns the version of the Java Programming Language supported by this Doclet.
   *
   * <p>This Doclet supports Java 5.
   *
   * @see com.sun.javadoc.Doclet#languageVersion()
   *
   * @return {@value LanguageVersion#JAVA_1_5}
   */
  public static LanguageVersion languageVersion() {
    return LanguageVersion.JAVA_1_5;
  }

  /**
   * Returns the number of arguments required for the given option.
   *
   * <p>This method calls {@link Options#getLength(String)}.
   *
   * @see com.sun.javadoc.Doclet#optionLength(String)
   * @see Options#getLength(String)
   *
   * @param option The name of the option.
   *
   * @return The number of arguments for that option.
   */
  public static int optionLength(String option) {
    return Options.getLength(option);
  }

  /**
   * Check that options have the correct arguments.
   *
   * <p>This method is not required, but is recommended, as every option will be considered valid
   * if this method is not present. It will default gracefully (to true) if absent.
   *
   * <p>Printing option related error messages (using the provided DocErrorReporter) is the
   * responsibility of this method.
   *
   * @see com.sun.javadoc.Doclet#validOptions(String[][], DocErrorReporter)
   *
   * @param options The two dimensional array of options.
   * @param reporter The error reporter.
   *
   * @return <code>true</code> if the options are valid.
   */
  public static boolean validOptions(String o[][], DocErrorReporter reporter) {
    options = Options.toOptions(o, reporter);
    // OK if we could set up the options.
    return options != null;
  }

  // Methods specific to this doclet implementation ===============================================

  /**
   * Save the given array of nodes.
   *
   * Will either save the files individually, or as a single file depending on the existence of the "-multiple" flag.
   *
   * @param nodes The array of nodes to be saved.
   */
  private static void save(List<XMLNode> nodes) {
    // Add admin node
    XMLNode meta = new XMLNode("meta");
    DateFormat df = new SimpleDateFormat(ISO_8601);
    meta.attribute("created", df.format(new Date()));

    // Multiple files
    if (options.useMultipleFiles()) {
      for (XMLNode node : nodes) {
        File dir = options.getDirectory();
        String name = node.getAttribute("name");
        if (options.useSubFolders()) {
          name = name.replace('.', '/');
          int x = name.lastIndexOf('/');
          if (x >= 0) {
            dir = new File(dir, name.substring(0,x));
            dir.mkdirs();
            name = name.substring(x+1);
          }
        }
        XMLNode root = new XMLNode("root");
        root.attribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
        root.child(meta);
        root.child(node);
        String fileName = name + ".xml";
        root.save(dir, fileName, options.getEncoding(), "");
      }
      // Index
      XMLNode root = new XMLNode("root");
      root.attribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
      root.child(meta);
      for (XMLNode node : nodes) {
        String name = node.getAttribute("name");
        if (options.useSubFolders()) name = name.replace('.', '/');
        XMLNode ref = new XMLNode(node.getName());
        ref.attribute("xlink:type", "simple");
        ref.attribute("xlink:href", name + ".xml");
        root.child(ref);
      }
      String fileName = "index.xml";
      root.save(options.getDirectory(), fileName, options.getEncoding(), "");

    // Single file
    } else {
      // Wrap the XML
      XMLNode root = new XMLNode("root");
      root.attribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
      root.child(meta);
      for (XMLNode node : nodes) {
        root.child(node);
      }
      root.save(options.getDirectory(), options.getFilename(), options.getEncoding(), "");
    }

  }

  /**
   * Returns the XML nodes for all the selected classes in the specified RootDoc.
   *
   * @param root The RootDoc from which the XML should be built.
   * @return The list of XML nodes which represents the RootDoc.
   */
  private static List<XMLNode> toXMLNodes(RootDoc root) {
    List<XMLNode> nodes = new ArrayList<XMLNode>();

    // Iterate over the classes
    for (ClassDoc doc : root.classes()) {
      if (options.filter(doc)) {
        nodes.add(toClassNode(doc));
      }
    }

    // Iterate over packages
    if (!options.hasFilter()) {
{'fraction_non_alphanumeric': 0.13211678832116788, 'fraction_numerical': 0.005766423357664234, 'mean_word_length': 3.0237885462555067, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 7, 'xml': 13}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5206605', 'n_tokens_mistral': 4207, 'n_tokens_neox': 4066, 'n_words': 1195}