package com.hubspot.jinjava.doc; import java.lang.reflect.Method; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Throwables; import com.hubspot.jinjava.Jinjava; import com.hubspot.jinjava.doc.annotations.JinjavaMetaValue; import com.hubspot.jinjava.doc.annotations.JinjavaParam; import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; import com.hubspot.jinjava.lib.exptest.ExpTest; import com.hubspot.jinjava.lib.filter.Filter; import com.hubspot.jinjava.lib.fn.ELFunctionDefinition; import com.hubspot.jinjava.lib.fn.InjectedContextFunctionProxy; import com.hubspot.jinjava.lib.tag.EndTag; import com.hubspot.jinjava.lib.tag.Tag; public class JinjavaDocFactory { private static final Logger LOG = LoggerFactory.getLogger(JinjavaDocFactory.class); private final Jinjava jinjava; public JinjavaDocFactory(Jinjava jinjava) { this.jinjava = jinjava; } public JinjavaDoc get() { JinjavaDoc doc = new JinjavaDoc(); addExpTests(doc); addFilterDocs(doc); addFnDocs(doc); addTagDocs(doc); return doc; } private void addExpTests(JinjavaDoc doc) { for (ExpTest t : jinjava.getGlobalContext().getAllExpTests()) { com.hubspot.jinjava.doc.annotations.JinjavaDoc docAnnotation = t.getClass().getAnnotation(com.hubspot.jinjava.doc.annotations.JinjavaDoc.class); if (docAnnotation == null) { LOG.warn("Expression Test {} doesn't have a @{} annotation", t.getName(), com.hubspot.jinjava.doc.annotations.JinjavaDoc.class.getName()); doc.addExpTest(new JinjavaDocExpTest(t.getName(), "", "", false, new JinjavaDocParam[] {}, new JinjavaDocSnippet[] {}, Collections.emptyMap())); } else if (!docAnnotation.hidden()) { doc.addExpTest(new JinjavaDocExpTest(t.getName(), docAnnotation.value(), docAnnotation.aliasOf(), docAnnotation.deprecated(), extractParams(docAnnotation.params()), extractSnippets(docAnnotation.snippets()), extractMeta(docAnnotation.meta()))); } } } private void addFilterDocs(JinjavaDoc doc) { for (Filter f : jinjava.getGlobalContext().getAllFilters()) { com.hubspot.jinjava.doc.annotations.JinjavaDoc docAnnotation = f.getClass().getAnnotation(com.hubspot.jinjava.doc.annotations.JinjavaDoc.class); if (docAnnotation == null) { LOG.warn("Filter {} doesn't have a @{} annotation", f.getClass(), com.hubspot.jinjava.doc.annotations.JinjavaDoc.class.getName()); doc.addFilter(new JinjavaDocFilter(f.getName(), "", "", false, new JinjavaDocParam[] {}, new JinjavaDocSnippet[] {}, Collections.emptyMap())); } else if (!docAnnotation.hidden()) { doc.addFilter(new JinjavaDocFilter(f.getName(), docAnnotation.value(), docAnnotation.aliasOf(), docAnnotation.deprecated(), extractParams(docAnnotation.params()), extractSnippets(docAnnotation.snippets()), extractMeta(docAnnotation.meta()))); } } } private void addFnDocs(JinjavaDoc doc) { for (ELFunctionDefinition fn : jinjava.getGlobalContext().getAllFunctions()) { if (StringUtils.isBlank(fn.getNamespace())) { Method realMethod = fn.getMethod(); if (realMethod.getDeclaringClass().getName().contains(InjectedContextFunctionProxy.class.getSimpleName())) { try { realMethod = (Method) realMethod.getDeclaringClass().getField("delegate").get(null); } catch (Exception e) { throw Throwables.propagate(e); } } com.hubspot.jinjava.doc.annotations.JinjavaDoc docAnnotation = realMethod.getAnnotation(com.hubspot.jinjava.doc.annotations.JinjavaDoc.class); if (docAnnotation == null) { LOG.warn("Function {} doesn't have a @{} annotation", fn.getName(), com.hubspot.jinjava.doc.annotations.JinjavaDoc.class.getName()); doc.addFunction(new JinjavaDocFunction(fn.getLocalName(), "", "", false, new JinjavaDocParam[] {}, new JinjavaDocSnippet[] {}, Collections.emptyMap())); } else if (!docAnnotation.hidden()) { doc.addFunction(new JinjavaDocFunction(fn.getLocalName(), docAnnotation.value(), docAnnotation.aliasOf(), docAnnotation.deprecated(), extractParams(docAnnotation.params()), extractSnippets(docAnnotation.snippets()), extractMeta(docAnnotation.meta()))); } } } } private void addTagDocs(JinjavaDoc doc) { for (Tag t : jinjava.getGlobalContext().getAllTags()) { if (t instanceof EndTag) { continue; } com.hubspot.jinjava.doc.annotations.JinjavaDoc docAnnotation = t.getClass().getAnnotation(com.hubspot.jinjava.doc.annotations.JinjavaDoc.class); if (docAnnotation == null) { LOG.warn("Tag {} doesn't have a @{} annotation", t.getName(), com.hubspot.jinjava.doc.annotations.JinjavaDoc.class.getName()); doc.addTag(new JinjavaDocTag(t.getName(), StringUtils.isBlank(t.getEndTagName()), "", "", false, new JinjavaDocParam[] {}, new JinjavaDocSnippet[] {}, Collections.emptyMap())); } else if (!docAnnotation.hidden()) { doc.addTag(new JinjavaDocTag(t.getName(), StringUtils.isBlank(t.getEndTagName()), docAnnotation.value(), docAnnotation.aliasOf(), docAnnotation.deprecated(), extractParams(docAnnotation.params()), extractSnippets(docAnnotation.snippets()), extractMeta(docAnnotation.meta()))); } } } private JinjavaDocParam[] extractParams(JinjavaParam[] params) { JinjavaDocParam[] result = new JinjavaDocParam[params.length]; for (int i = 0; i < params.length; i++) { JinjavaParam p = params[i]; result[i] = new JinjavaDocParam(p.value(), p.type(), p.desc(), p.defaultValue()); } return result; } private JinjavaDocSnippet[] extractSnippets(JinjavaSnippet[] snippets) { JinjavaDocSnippet[] result = new JinjavaDocSnippet[snippets.length]; for (int i = 0; i < snippets.length; i++) { JinjavaSnippet s = snippets[i]; result[i] = new JinjavaDocSnippet(s.desc(), s.code(), s.output()); } return result; } private Map<String, String> extractMeta(JinjavaMetaValue[] metaValues) { Map<String, String> meta = new LinkedHashMap<>(); for (JinjavaMetaValue metaValue : metaValues) { meta.put(metaValue.name(), metaValue.value()); } return meta; } }