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

io.sarl.maven.docs.generator.SARLDocGenerator Maven / Gradle / Ivy

There is a newer version: 0.12.0
Show newest version
/*
 * $Id: io/sarl/maven/docs/generator/SARLDocGenerator.java v0.3.1 2016-01-23 23:01:10$
 *
 * SARL is an general-purpose agent programming language.
 * More details on http://www.sarl.io
 *
 * Copyright (C) 2014-2015 the original authors or authors.
 *
 * 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.
 */

package io.sarl.maven.docs.generator;

import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.collect.Lists;
import com.google.inject.Inject;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtend.core.xtend.XtendClass;
import org.eclipse.xtend.core.xtend.XtendMember;
import org.eclipse.xtend.core.xtend.XtendPackage.Literals;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.jnario.ExampleTable;
import org.jnario.doc.AbstractDocGenerator;
import org.jnario.doc.Filter;
import org.jnario.doc.FilterExtractor;
import org.jnario.doc.FilteringResult;
import org.jnario.doc.HtmlAssets;
import org.jnario.doc.HtmlFile;
import org.jnario.spec.naming.ExampleNameProvider;
import org.jnario.spec.spec.Example;
import org.jnario.spec.spec.ExampleGroup;
import org.jnario.util.Strings;

/** Generator of the HTML files for the SARL documentation.
 * Copied from SpecDocGenerator (version 1.0.0).
 *
 * @author Stéphane Galland
 * @version 0.3.1 2016-01-23 23:01:10
 * @mavengroupid io.sarl.maven
 * @mavenartifactid io.sarl.maven.docs.generator
 */
class SARLDocGenerator extends AbstractDocGenerator {

	/** Maximal depth that may be referred in the outline.
	 */
	protected static final int MAX_DEPTH_REFERENCING = 9;

	/** List of the markes that should be replaced by the outline.
	 */
	protected static final String[] OUTLINE_MARKERS = new String[] {
		Matcher.quoteReplacement(""), //$NON-NLS-1$
		Matcher.quoteReplacement("@outline"), //$NON-NLS-1$
	};

	/** Separator for the IDs.
	 */
	protected static final String ID_SEPARATOR = "_"; //$NON-NLS-1$

	@Inject
	private ExampleNameProvider nameProvider;

	@Inject
	private FilterExtractor filterExtractor;

	@Inject
	private HtmlAssets htmlAsserts;

	/** Construct the documentation generator.
	 */
	SARLDocGenerator() {
		//
	}

	@Override
	public HtmlFile createHtmlFile(final XtendClass xtendClass) {
		if (!(xtendClass instanceof ExampleGroup)) {
			return HtmlFile.EMPTY_FILE;
		}
		final ExampleGroup exampleGroup = (ExampleGroup) xtendClass;
		return HtmlFile.newHtmlFile(new Procedure1() {
			@SuppressWarnings("synthetic-access")
			@Override
			public void apply(HtmlFile it) {
				it.setAssets(SARLDocGenerator.this.htmlAsserts);
				it.setName(SARLDocGenerator.this.nameProvider.toJavaClassName(exampleGroup));
				it.setTitle(asTitle(exampleGroup));
				it.setContent(generateRootContent(exampleGroup));
				it.setRootFolder(root(exampleGroup));
				it.setSourceCode(pre(xtendClass.eContainer(), "lang-spec")); //$NON-NLS-1$
				it.setFileName(fileName(xtendClass));
				it.setExecutionStatus(executionStateClass(exampleGroup));
			}
		});
	}

	/** Replies the HTML title of the given object.
	 *
	 * @param object - the object.
	 * @return the HTML title.
	 */
	protected String asTitle(EObject object) {
		return toTitle(this.nameProvider.describe(object));
	}

	/** Replies the HTML code for the code part of a fact.
	 *
	 * @param example - the fact.
	 * @param filters - the filters to apply to the code of the fact.
	 * @return the HTML code.
	 */
	protected String toCodeBlock(Example example, List filters) {
		String code = serialize(example.getExpression(), filters);
		if (code == null || code.isEmpty()) {
			return ""; //$NON-NLS-1$
		}
		String prefix = "
"; //$NON-NLS-1$
		prefix = apply(filters, prefix);
		if (prefix == null || prefix.isEmpty()) {
			return code;
		}
		return prefix + code + "
\n"; //$NON-NLS-1$ } /** Replies the HTML tag that corresponds to a title at the given level * for the given object. * * @param object - the provider of the title text. * @param sectionNumber - the section numbering from the root to the current object. * @return the HTML tag for the title. */ protected String makeTitleTag(EObject object, SectionNumber sectionNumber) { int depth = sectionNumber.getDepth(); if (depth < MAX_DEPTH_REFERENCING) { String depthLevel = Integer.toString(depth + 1); return "" + sectionNumber.toHTML() //$NON-NLS-1$ + asTitle(object) + "\n"; //$NON-NLS-1$//$NON-NLS-2$ } return "" + asTitle(object) //$NON-NLS-1$ + "

\n"; //$NON-NLS-1$ } /** Protect the value of an ID. * This function is similar to {@link #id(String)}, * except that the prefix id= is not appended. * * @param id - the id to protect. * @return the protected ID. */ protected static String protectID(String id) { if (id != null) { String protectedId = id.replaceAll("\\W+", ID_SEPARATOR); //$NON-NLS-1$ if (protectedId != null) { return Strings.trim(protectedId, ID_SEPARATOR.charAt(0)); } } return ""; //$NON-NLS-1$ } /** Replies the HTML tag that corresponds to a reference to a title. * * @param object - the provider of the title text. * @param sectionNumber - the section numbering from the root to the current object. * @param text - the text of the reference. * @return the HTML tag for the title. */ protected String makeTitleHref(EObject object, SectionNumber sectionNumber, String text) { return "" + sectionNumber.toHTML() //$NON-NLS-1$ + text + ""; //$NON-NLS-1$ } /** Generate the complete documentation for the given group. * * @param group - the object from which the documentation must be generated. * @return the HTML representation of the table. */ @SuppressWarnings("synthetic-access") private String generateRootContent(ExampleGroup group) { List outline = Lists.newArrayList(); StringConcatenation content = generateMembers(group, new SectionNumber(), outline); String topDoc = postProcess(generateDoc(group), outline); return topDoc + content; } /** Post process the top documentation. * * @param text - the original value of the top documentation. * @param outline - the outline entries. * @return the top documentation to use. */ @SuppressWarnings("static-method") protected String postProcess(String text, List outline) { String outlineText; if (outline != null && !outline.isEmpty()) { StringBuilder b = new StringBuilder(); b.append("
    "); //$NON-NLS-1$ for (String line : outline) { if (line != null && !line.isEmpty()) { b.append("
  • "); //$NON-NLS-1$ b.append(line); b.append("
  • \n"); //$NON-NLS-1$ } } b.append("
"); //$NON-NLS-1$ outlineText = b.toString(); } else { outlineText = ""; //$NON-NLS-1$ } String refactoredText = text; for (String pattern : OUTLINE_MARKERS) { refactoredText = refactoredText.replaceAll(pattern, outlineText); } return refactoredText; } /** Post process an HTML documentation. * * @param text - the original value of the documentation. * @return the documentation to use. */ @SuppressWarnings("static-method") protected String postProcess(String text) { String refactoredText = text; for (NoteTag tag : NoteTag.values()) { refactoredText = tag.apply(refactoredText); } refactoredText = refactoredText.replaceAll("(

){2,}", "

"); //$NON-NLS-1$//$NON-NLS-2$ refactoredText = refactoredText.replaceAll("(

){2,}", "

"); //$NON-NLS-1$//$NON-NLS-2$ return refactoredText; } /** Generate the HTML code from the Markdown text * of the given object. * * @param object - the object from which the Markdown text should be extract. * @return the HTML representation of the table. */ protected final String generateDoc(EObject object) { String doc = documentation(object); if (doc != null && !doc.isEmpty()) { return postProcess(markdown2Html(doc)); } return ""; //$NON-NLS-1$ } /** Generate the HTML code for the members of an example group.. * * @param group - the example group. * @param sectionNumber - the section numbering from the root to the current object. * @return the HTML representation of the table. */ protected final StringConcatenation generateMembers(ExampleGroup group, SectionNumber sectionNumber) { return generateMembers(group, sectionNumber, null); } /** Generate the HTML code for the members of an example group.. * * @param group - the example group. * @param sectionNumber - the section numbering from the root to the current object. * @param outline - the list of the entries for the outline. * @return the HTML representation of the table. */ @SuppressWarnings("checkstyle:npathcomplexity") private StringConcatenation generateMembers(ExampleGroup group, SectionNumber sectionNumber, List outline) { StringConcatenation result = new StringConcatenation(); String content; String hrefLabel; SectionNumber childNumber; boolean isRoot = sectionNumber.isRoot(); boolean isFlatSections = sectionNumber.isMaxDepthReferencing(); if (isFlatSections) { result.append("
    "); //$NON-NLS-1$ } int position = 0; for (XtendMember member : group.getMembers()) { if (member instanceof Example) { Example example = (Example) member; childNumber = sectionNumber.getChild(position); hrefLabel = makeTitleHref(example, childNumber, asTitle(example)); content = generate(example, childNumber); ++position; } else if (member instanceof ExampleGroup) { ExampleGroup sgroup = (ExampleGroup) member; childNumber = sectionNumber.getChild(position); hrefLabel = makeTitleHref(sgroup, childNumber, asTitle(sgroup)); content = generate(sgroup, childNumber); ++position; } else if (member instanceof ExampleTable) { ExampleTable table = (ExampleTable) member; childNumber = sectionNumber.getChild(position); hrefLabel = makeTitleHref(table, childNumber, asTitle(table)); content = generate(table, childNumber); ++position; } else { content = null; hrefLabel = null; } if (content != null && !content.isEmpty()) { if (isFlatSections) { result.append("
  • "); //$NON-NLS-1$ } result.append(content); if (isFlatSections) { result.append("
  • "); //$NON-NLS-1$ } else if (isRoot && outline != null && hrefLabel != null && !hrefLabel.isEmpty()) { outline.add(hrefLabel); } } } if (isFlatSections) { result.append("
"); //$NON-NLS-1$ } return result; } /** Generate the HTML code for the given example. * * @param example - the example. * @param sectionNumber - the section numbering from the root to the current object. * @return the HTML representation of the table. */ protected String generate(Example example, SectionNumber sectionNumber) { String documentation = documentation(example); List filters; if (documentation != null && !documentation.isEmpty()) { FilteringResult result = this.filterExtractor.apply(documentation); filters = result.getFilters(); documentation = result.getString(); documentation = postProcess(markdown2Html(documentation)); } else { filters = Collections.emptyList(); } String exampleName = example.getName(); StringBuilder result = new StringBuilder(); if (exampleName != null && !exampleName.isEmpty()) { result.append(makeTitleTag(example, sectionNumber)); } result.append(documentation); if (!example.isPending() && example.eIsSet(Literals.XTEND_EXECUTABLE__EXPRESSION)) { result.append(toCodeBlock(example, filters)); } result.append(errorMessage(example)); return result.toString(); } /** Generate the HTML code for the given example group. * * @param group - the example group. * @param sectionNumber - the section numbering from the root to the current object. * @return the HTML representation of the table. */ protected String generate(ExampleGroup group, SectionNumber sectionNumber) { return makeTitleTag(group, sectionNumber) + generateDoc(group) + generateMembers(group, sectionNumber); } /** Generate the HTML code for the given example table. * * @param table - the example table. * @param sectionNumber - the section numbering from the root to the current object. * @return the HTML representation of the table. */ protected String generate(ExampleTable table, SectionNumber sectionNumber) { return "" //$NON-NLS-1$ + toTitle(this.nameProvider.toFieldName(table)) + "

" //$NON-NLS-1$ + generateDoc(table) + super.generate(table); } /** A section number. * * @author Stéphane Galland * @version 0.3.1 2016-01-23 23:01:10 * @mavengroupid io.sarl.maven * @mavenartifactid io.sarl.maven.docs.generator */ protected final class SectionNumber { private final SectionNumber parent; private final int position; private final int depth; /** Create the first root section. */ private SectionNumber() { this(null, 0); } /** Create the first section in the given parent. * * @param parent - parent number section. * @param position - index in the given parent. */ private SectionNumber(SectionNumber parent, int position) { this.parent = parent; this.position = position; if (this.parent != null) { this.depth = parent.getDepth() + 1; } else { this.depth = 1; } } /** Replies the depth of the section. * * @return the depth of the section. */ public int getDepth() { return this.depth; } /** Replies the HTML representation of this section number. * * @return the HTML representation of this section number. */ public String toHTML() { if (MavenConfig.isSectionNumbering() && this.position > 0) { String txt = toString(); if (txt != null && !txt.isEmpty()) { return txt + " "; //$NON-NLS-1$ } return txt; } return ""; //$NON-NLS-1$ } @Override public String toString() { if (MavenConfig.isSectionNumbering() && this.position > 0) { StringBuilder b = new StringBuilder(); if (this.parent != null) { b.append(this.parent.toString()); } b.append(Integer.valueOf(this.position)); b.append("."); //$NON-NLS-1$ return b.toString(); } return ""; //$NON-NLS-1$ } /** Replies the section number of the child at the given position. * * @param index - position of the child, starting from zero. * @return the section number of the first child. */ public SectionNumber getChild(int index) { return new SectionNumber(this, index + 1); } /** Replies if the section number is greater to the max depth * for referencing them. * * @return true if greater than max depth. */ public boolean isMaxDepthReferencing() { return this.depth > MAX_DEPTH_REFERENCING; } /** Replies if the section number is for a root section. * * @return true if the number is for root section. */ public boolean isRoot() { return this.depth == 1; } } /** HTML tags that could be used to put marked sections in the text. * * @author Stéphane Galland * @version 0.3.1 2016-01-23 23:01:10 * @mavengroupid io.sarl.maven * @mavenartifactid io.sarl.maven.docs.generator */ protected enum NoteTag { /** A note. */ NOTE("note", "label-info", "Note"), //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ /** An important note. */ IMPORTANT("importantnote", "label-warning", "Important"), //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ /** A caution note. */ CAUTION("cautionnote", "label-warning", "Caution"), //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ /** An very important note. */ DANGER("veryimportantnote", "label-danger", "Important"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ private final String htmlTag; private final String htmlLabel; private final String text; /** * @param htmlTag - the HTML tag. * @param htmlLabel - the HTML label. * @param text - the text. */ NoteTag(String htmlTag, String htmlLabel, String text) { this.htmlTag = htmlTag; this.htmlLabel = htmlLabel; this.text = text; } /** Format a text according to the current note tag. * * @param text - the text to format. * @return the formated string. */ public String apply(String text) { Pattern pattern = Pattern.compile( "<" + this.htmlTag //$NON-NLS-1$ + "(?:\\s+label\\s*=\\s*\"(.*?)\")?" //$NON-NLS-1$ + "\\s*>" //$NON-NLS-1$ + "(.*?)" //$NON-NLS-1$ + "", //$NON-NLS-1$//$NON-NLS-2$ Pattern.DOTALL); Matcher matcher = pattern.matcher(text); StringBuffer b = new StringBuffer(); while (matcher.find()) { String label = matcher.group(1); String htmlText = matcher.group(2).trim(); if (label == null) { label = this.text; } else { label = label.trim(); } String replacement = "

" + label + " " //$NON-NLS-1$//$NON-NLS-2$ + htmlText + "

"; //$NON-NLS-1$ matcher.appendReplacement(b, replacement); } matcher.appendTail(b); return b.toString(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy