001package io.jstach.jstachio;
002
003import java.nio.charset.Charset;
004import java.nio.charset.StandardCharsets;
005import java.util.function.Function;
006
007import org.eclipse.jdt.annotation.Nullable;
008
009import io.jstach.jstache.JStacheConfig;
010import io.jstach.jstache.JStacheContentType;
011import io.jstach.jstache.JStacheType;
012
013/**
014 * Template meta data like its location, formatters, escapers and or its contents.
015 * <p>
016 * This data is usually available on generated {@link Template}s.
017 *
018 * @author agentgt
019 */
020public interface TemplateInfo {
021
022        /**
023         * The template instance is accessible to mustache templates with this global binding
024         * name. <strong>This is not bound if template is type
025         * {@link JStacheType#STACHE}.</strong>
026         */
027        public static String TEMPLATE_BINDING_NAME = "@template";
028
029        /**
030         * The logical name of the template which maybe different than
031         * {@link #templatePath()}.
032         * @return logical name of template. Never null.
033         */
034        public String templateName();
035
036        /**
037         * If the template is a classpath resource file this will return the location that was
038         * originally resolved via {@linkplain JStacheConfig config resolution}.
039         * @return the location of the template or empty if the template is inlined.
040         * @apiNote since the return is the original path resolved by the annotation processor
041         * it may return a path with a starting "/" and thus it is recommend you call
042         * {@link #normalizePath()} if you plan on loading the resource.
043         *
044         * @see #normalizePath()
045         */
046        public String templatePath();
047
048        /**
049         * Normalizes the path to used by {@link ClassLoader#getResource(String)}.
050         *
051         * If the templatePath starts with a "/" it is stripped.
052         * @return normalized path
053         */
054        default String normalizePath() {
055                String p = templatePath();
056                if (p.startsWith("/")) {
057                        return p.substring(1);
058                }
059                return p;
060        }
061
062        /**
063         * The raw contents of the template. Useful if the template is inline. To determine if
064         * the template is actually inline use {@link #templateSource()}.
065         * @apiNote An empty or blank template string maybe a valid inline template and does
066         * not mean it is not inline.
067         * @return the raw contents of the template never null.
068         * @see TemplateSource
069         */
070        default String templateString() {
071                return "";
072        }
073
074        /**
075         * The template content type is the class annotated with {@link JStacheContentType}
076         * which also describes the escaper to be used.
077         * @apiNote The class returned must be annotated with {@link JStacheContentType}.
078         * @return the template content type.
079         */
080        Class<?> templateContentType();
081
082        /**
083         * The template {@link Charset} which is the original format of the template file and
084         * should ideally be used when encoding an HTTP response or similar. Furthermore
085         * ideally the template charset matches the chosen {@link #templateContentType()}
086         * {@link JStacheContentType#charsets()} otherwise the escaper may not appropriately
087         * escape.
088         * <p>
089         * IF the template is inline or charset was not set this will usually be
090         * {@link StandardCharsets#UTF_8}.
091         * @return the template Charset.
092         * @see JStacheContentType#charsets()
093         * @see JStacheConfig#charset()
094         */
095        Charset templateCharset();
096
097        /**
098         * The template media-type from the {@link JStacheContentType}.
099         * @return media type maybe an empty string.
100         */
101        String templateMediaType();
102
103        /**
104         * The escaper to be used on the template. See {@link Escaper#of(Function)}.
105         * @apiNote While the return signature is {@link Function} the function is often an
106         * {@link Escaper} but does not have to be.
107         * @return the escaper.
108         * @see Escaper
109         */
110        Function<String, String> templateEscaper();
111
112        /**
113         * The base formatter to be used on the template. See {@link Formatter#of(Function)}.
114         * @apiNote While the return signature is {@link Function} the function is often a
115         * {@link Formatter} but does not have to be.
116         * @return the formatter.
117         * @see Formatter
118         */
119        @SuppressWarnings("exports")
120        Function<@Nullable Object, String> templateFormatter();
121
122        /**
123         * Checks to see if a template supports the model class.
124         * @param type the class of the model.
125         * @return if this renderer supports the class.
126         */
127        public boolean supportsType(Class<?> type);
128
129        /**
130         * Return the model class (root context class annotated with JStache) that generated
131         * this template.
132         * @return model class
133         */
134        public Class<?> modelClass();
135
136        /**
137         * Where the template contents were retrieved from.
138         * @return an enum never null.
139         */
140        default TemplateSource templateSource() {
141                return templatePath().isEmpty() ? TemplateSource.STRING : TemplateSource.RESOURCE;
142        }
143
144        /**
145         * Symbols representing where the template was retrieved from.
146         * @author agentgt
147         */
148        public enum TemplateSource {
149
150                /**
151                 * Template was retrieved from the classpath at compile time.
152                 */
153                RESOURCE,
154                /**
155                 * Template was inlined as a String literal
156                 */
157                STRING
158
159        }
160
161        /**
162         * The last loaded time if applicable.
163         *
164         * For statically compiled templates this will always be a negative number. For
165         * dynamically loaded templates this more likely will return a non negative number
166         * indicating some hint of when the template was last modified or loaded.
167         * @return the last modified or negative if not applicable
168         */
169        default long lastLoaded() {
170                return -1;
171        }
172
173        /**
174         * Utility method similar to toString that describes the template meta data.
175         * @return description of the template.
176         */
177        default String description() {
178                return String.format("TemplateInfo[name=%s, path=%s, contentType=%s, charset=%s]", templateName(),
179                                templatePath(), templateContentType(), templateCharset());
180        }
181
182}