Package com.getperka.flatpack.fast

Source Code of com.getperka.flatpack.fast.JavaScriptDialect

package com.getperka.flatpack.fast;

/*
* #%L
* FlatPack Automatic Source Tool
* %%
* Copyright (C) 2012 - 2013 Perka Inc.
* %%
* 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 java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.stringtemplate.v4.AttributeRenderer;
import org.stringtemplate.v4.AutoIndentWriter;
import org.stringtemplate.v4.Interpreter;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;
import org.stringtemplate.v4.misc.ObjectModelAdaptor;
import org.stringtemplate.v4.misc.STNoSuchPropertyException;

import com.getperka.cli.flags.Flag;
import com.getperka.flatpack.BaseHasUuid;
import com.getperka.flatpack.client.dto.ApiDescription;
import com.getperka.flatpack.client.dto.EndpointDescription;
import com.getperka.flatpack.client.dto.ParameterDescription;
import com.getperka.flatpack.ext.EntityDescription;
import com.getperka.flatpack.ext.JsonKind;
import com.getperka.flatpack.ext.Property;
import com.getperka.flatpack.ext.Type;
import com.getperka.flatpack.util.FlatPackCollections;

public class JavaScriptDialect implements Dialect {

  @Flag(tag = "packageName",
      help = "The name of the package that generated sources should belong to",
      defaultValue = "com.getperka.client")
  static String packageName;

  private static final Logger logger = LoggerFactory.getLogger(JavaScriptDialect.class);

  private static final Map<String, String> validationMap = new HashMap<String, String>();

  static {

    validationMap.put("javax.validation.Valid",
        "com.getperka.flatpack.validation.Valid");
    validationMap.put("javax.validation.constraints.AssertFalse",
        "com.getperka.flatpack.validation.AssertFalse");
    validationMap.put("javax.validation.constraints.AssertTrue",
        "com.getperka.flatpack.validation.AssertTrue");
    validationMap.put("javax.validation.constraints.DecimalMax",
        "com.getperka.flatpack.validation.Max");
    validationMap.put("javax.validation.constraints.DecimalMin",
        "com.getperka.flatpack.validation.Min");
    validationMap.put("javax.validation.constraints.Future",
        "com.getperka.flatpack.validation.Future");
    validationMap.put("javax.validation.constraints.Min",
        "com.getperka.flatpack.validation.Min");
    validationMap.put("javax.validation.constraints.Max",
        "com.getperka.flatpack.validation.Max");
    validationMap.put("javax.validation.constraints.NotNull",
        "com.getperka.flatpack.validation.NotNull");
    validationMap.put("javax.validation.constraints.Null",
        "com.getperka.flatpack.validation.Null");
    validationMap.put("javax.validation.constraints.Past",
        "com.getperka.flatpack.validation.Past");
    validationMap.put("javax.validation.constraints.Size",
        "com.getperka.flatpack.validation.Size");

    // validationMap.put("javax.validation.constraints.Digits",
    // "com.getperka.flatpack.validation.");
    // validationMap.put("javax.validation.constraints.Pattern",
    // "com.getperka.flatpack.validation.");
  }

  private static String upcase(String s) {
    return Character.toUpperCase(s.charAt(0)) + s.substring(1);
  }

  private EntityDescription baseHasUuid;
  private List<String> entityRequires;

  @Override
  public void generate(ApiDescription api, File outputDir) throws IOException {

    if (!outputDir.isDirectory() && !outputDir.mkdirs()) {
      logger.error("Could not create output directory {}", outputDir.getPath());
      return;
    }

    // first collect just our model entities
    Set<String> requires = new HashSet<String>();
    Map<String, EntityDescription> allEntities =
        FlatPackCollections.mapForIteration();

    for (EntityDescription entity : api.getEntities()) {
      addEntity(allEntities, requires, entity);
    }

    entityRequires = new ArrayList<String>(requires);
    Collections.sort(entityRequires);

    // Render entities
    STGroup group = loadGroup();
    ST entityST = null;
    for (EntityDescription entity : allEntities.values()) {
      entityST = group.getInstanceOf("entity").add("entity", entity);
      render(entityST, outputDir, camelCaseToUnderscore(entity.getTypeName()) + ".js");
    }

    // render api stubs
    ST apiST = group.getInstanceOf("api").add("api", api);
    render(apiST, outputDir, "generated_base_api.js");
  }

  @Override
  public String getDialectName() {
    return "js";
  }

  /**
   * Adds an entity and its supertypes to a map. The properties defined by the entity will be pruned
   * so that the entity contains only its declared properties.
   *
   * @param allEntities an accumulator map of entity payload names to descriptions
   * @param entity the entity to add
   */
  protected void addEntity(Map<String, EntityDescription> allEntities,
      Set<String> requires, EntityDescription entity) {

    if (entity == null) {
      return;
    }

    String typeName = entity.getTypeName();

    if (allEntities.containsKey(typeName)) {
      // Already processed
      return;
    } else if ("baseHasUuid".equals(typeName)) {
      // Ensure that the "real" implementations are used
      baseHasUuid = entity;
      return;
    } else if ("hasUuid".equals(typeName)) {
      // Ensure that the "real" implementations are used
      return;
    }

    allEntities.put(typeName, entity);
    for (Iterator<Property> it = entity.getProperties().iterator(); it.hasNext();) {
      Property prop = it.next();
      if ("uuid".equals(prop.getName())) {
        // Crop the UUID property
        it.remove();
      } else if (!prop.getEnclosingType().equals(entity)) {
        // Remove properties not declared in the current type
        it.remove();
      }
    }

    requires.add(getPackageName(entity) + "." + upcase(entity.getTypeName()));

    // Add the supertype
    addEntity(allEntities, requires, entity.getSupertype());
  }

  private String camelCaseToUnderscore(String s) {
    return s.replaceAll(
        String.format("%s|%s|%s", "(?<=[A-Z])(?=[A-Z][a-z])",
            "(?<=[^A-Z])(?=[A-Z])", "(?<=[A-Za-z])(?=[^A-Za-z])"), "_")
        .toLowerCase();
  }

  private String collectionNameForProperty(Property p) {
    return upcase(p.getType().getListElement().getName()) + "Collection";
  }

  private String getBuilderReturnType(EndpointDescription end) {
    // Convert a path like /api/2/foo/bar/{}/baz to FooBarBazMethod
    String path = end.getPath();
    String[] parts = path.split(Pattern.quote("/"));
    StringBuilder sb = new StringBuilder();
    sb.append(upcase(end.getMethod().toLowerCase()));
    for (int i = 3, j = parts.length; i < j; i++) {
      try {
        String part = parts[i];
        if (part.length() == 0) {
          continue;
        }
        StringBuilder decodedPart = new StringBuilder(URLDecoder
            .decode(part, "UTF8"));
        // Trim characters that aren't legal
        for (int k = decodedPart.length() - 1; k >= 0; k--) {
          if (!Character.isJavaIdentifierPart(decodedPart.charAt(k))) {
            decodedPart.deleteCharAt(k);
          }
        }
        // Append the new name part, using camel-cased names
        String newPart = decodedPart.toString();
        if (sb.length() > 0) {
          newPart = upcase(newPart);
        }
        sb.append(newPart);
      } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
      }
    }
    sb.append("Request");

    return packageName + "." + upcase(sb.toString());
  }

  private String getNameForType(Type type) {
    String name = type.getName();
    name = name == null || name.trim().length() == 0 ? type.getJsonKind().name()
        .toLowerCase() : name;
    return name;
  }

  private String getPackageName(EntityDescription entity) {
    return entity.getTypeName().equals("baseHasUuid") ?
        "com.getperka.flatpack.core" : packageName;
  }

  private List<Property> getSortedCollectionProperties(EntityDescription entity) {
    List<Property> properties = new ArrayList<Property>();
    for (Property p : entity.getProperties()) {
      if (p.getType().getListElement() != null &&
        p.getType().getListElement().getName() != null) {
        properties.add(p);
      }
    }
    List<Property> sortedProperties = new ArrayList<Property>();
    sortedProperties.addAll(properties);
    Collections.sort(sortedProperties, new Comparator<Property>() {
      @Override
      public int compare(Property p1, Property p2) {
        return p1.getName().compareTo(p2.getName());
      }
    });
    return sortedProperties;
  }

  private String getValidationParameters(Annotation annotation) {
    String params = "";

    if (annotation instanceof Min) {
      params += ((Min) annotation).value();
    }

    if (annotation instanceof Max) {
      params += ((Max) annotation).value();
    }

    if (annotation instanceof DecimalMin) {
      params += ((DecimalMax) annotation).value();
    }

    if (annotation instanceof DecimalMax) {
      params += ((DecimalMax) annotation).value();
    }

    if (annotation instanceof Size) {
      Size size = (Size) annotation;
      params += size.min() + ", " + size.max();
    }

    return params;
  }

  private boolean hasCustomRequestBuilderClass(EndpointDescription end) {
    return (end.getQueryParameters() != null && !end.getQueryParameters().isEmpty()) ||
      (end.getReturnType() != null && end.getReturnType().getUuid() != null);
  }

  /**
   * Converts the given docString to be jsDoc compatible
   *
   * @param docString
   * @return
   */
  private String jsDocString(String docString) {
    if (docString == null) return docString;

    String newDocString = docString;
    try {
      // replace <entityReference> tags with /link /endlink pairs
      Pattern regex = Pattern.compile(
          "<entityReference payloadName='([^']*)'>([^<]*)</entityReference>",
          Pattern.CASE_INSENSITIVE);
      Matcher matcher = regex.matcher(docString);
      while (matcher.find()) {
        Type type = new Type.Builder().withName(matcher.group(1).trim()).build();
        String jsType = jsTypeForType(type);

        String link = "{@link " + jsType + "}";
        newDocString = newDocString.replaceAll(matcher.group(0), link);
      }

      // replace #getFoo() method calls to #foo() method calls
      regex = Pattern.compile(
          "#get([^(]*)" + Pattern.quote("()"),
          Pattern.CASE_INSENSITIVE);
      matcher = regex.matcher(docString);
      while (matcher.find()) {
        String newMethod = "#" + matcher.group(1);
        newDocString = newDocString.replaceAll(matcher.group(0), newMethod);
      }
    }

    catch (Exception e) {
      logger.error("Couldn't doxygenize doc string: " + docString, e);
    }
    return newDocString;
  }

  private String jsTypeForType(Type type) {
    if (type.getName() != null) {
      // if the type is an enum, the type will be a string
      if (type.getEnumValues() != null) {
        return "String";
      }
      return packageName + "." + upcase(type.getName());
    }

    if (type.getTypeHint() != null
      && type.getTypeHint().getValue().equals("org.joda.time.DateTime")) {
      return "Date";
    }
    else if (type.getTypeHint() != null
      && type.getTypeHint().getValue().equals("org.joda.time.LocalDateTime")) {
      return "LocalDate";
    }
    else if (type.getTypeHint() != null
      && (type.getTypeHint().getValue().equals("java.math.BigDecimal")
      || type.getTypeHint().getValue().equals("java.math.BigInteger"))) {
      return "Number";
    }

    String jsType = "nil";
    switch (type.getJsonKind()) {
      case BOOLEAN:
        jsType = "Boolean";
        break;
      case DOUBLE:
        jsType = "Number";
        break;
      case ANY:
        jsType = "Object";
        break;
      case INTEGER:
        jsType = "Number";
        break;
      case LIST:
        if (type.getListElement() != null && (type.getListElement().getEnumValues() != null ||
          type.getListElement().getName() == null)) {
          jsType = "Array";
        } else {
          jsType = "Backbone.Collection";
        }
        break;
      case MAP:
        jsType = "Object";
        break;
      case NULL:
        jsType = "null";
        break;
      case STRING:
        jsType = "String";
        break;
      default:
        break;
    }

    return jsType;
  }

  /**
   * Load {@code js.stg} from the classpath and configure a number of model adaptors to add virtual
   * properties to the objects being rendered.
   */
  private STGroup loadGroup() {

    STGroup group = new STGroupFile(getClass().getResource("js.stg"), "UTF8", '<', '>');
    group.registerRenderer(EntityDescription.class, new AttributeRenderer() {
      @Override
      public String toString(Object o, String formatString, Locale locale) {
        EntityDescription entity = (EntityDescription) o;
        if (entity.getTypeName().equals("baseHasUuid")) {
          return BaseHasUuid.class.getCanonicalName();
        }
        return entity.getTypeName();
      }
    });

    group.registerModelAdaptor(EntityDescription.class,
        new ObjectModelAdaptor() {
          @Override
          public Object getProperty(Interpreter interp, ST self, Object o,
              Object property, String propertyName)
              throws STNoSuchPropertyException {

            EntityDescription entity = (EntityDescription) o;
            if ("docString".equals(propertyName)) {
              return jsDocString(entity.getDocString());
            }

            else if ("canonicalName".equals(propertyName)) {
              return getPackageName(entity) + "." + upcase(entity.getTypeName());
            }

            else if ("supertype".equals(propertyName)) {
              EntityDescription supertype = entity.getSupertype();
              if (supertype == null) {
                supertype = baseHasUuid;
              }
              return supertype;
            }

            else if ("properties".equals(propertyName)) {

              Map<String, Property> propertyMap = new HashMap<String, Property>();
              for (Property p : entity.getProperties()) {
                propertyMap.put(p.getName(), p);
              }

              List<Property> sortedProperties = new ArrayList<Property>();
              sortedProperties.addAll(propertyMap.values());
              Collections.sort(sortedProperties, new Comparator<Property>() {
                @Override
                public int compare(Property p1, Property p2) {
                  return p1.getName().compareTo(p2.getName());
                }
              });

              return sortedProperties;
            }

            else if ("collectionProperties".equals(propertyName)) {
              return getSortedCollectionProperties(entity);
            }

            else if ("uniqueTypeCollectionListProperties".equals(propertyName)) {
              List<Property> props = getSortedCollectionProperties(entity);
              Iterator<Property> iter = props.iterator();

              Set<String> seen = new HashSet<String>();
              while (iter.hasNext()) {
                Property prop = iter.next();
                String name = collectionNameForProperty(prop);
                if (!seen.contains(name)) {
                  seen.add(name);
                }
                else {
                  iter.remove();
                }
              }
              return props;
            }

            else if ("validations".equals(propertyName)) {
              Map<String, List<String>> map = new HashMap<String, List<String>>();

              for (Property p : entity.getProperties()) {
                List<String> validations = new ArrayList<String>();

                List<Annotation> docAnnotations = p.getDocAnnotations();
                if (docAnnotations != null) {
                  for (Annotation a : docAnnotations) {
                    String name = a.annotationType().getName();

                    String validation = validationMap.get(name);
                    if (validation != null) {
                      validation = "new " + validation + "(";
                      validation += getValidationParameters(a);
                      validation += ")";
                      validations.add(validation);
                    }
                  }
                }

                if (!validations.isEmpty()) {
                  map.put(p.getName(), validations);
                }
              }
              return map;
            }

            else if ("validationRequires".equals(propertyName)) {
              Set<String> requires = new HashSet<String>();

              for (Property p : entity.getProperties()) {
                List<Annotation> docAnnotations = p.getDocAnnotations();
                if (docAnnotations != null) {
                  for (Annotation a : docAnnotations) {
                    String name = a.annotationType().getName();
                    String require = validationMap.get(name);
                    if (require != null) {
                      requires.add(require);
                    }
                  }
                }
              }

              return requires;
            }

            return super.getProperty(interp, self, o, property, propertyName);
          }

        });

    group.registerModelAdaptor(Property.class, new ObjectModelAdaptor() {
      @Override
      public Object getProperty(Interpreter interp, ST self, Object o,
          Object property, String propertyName)
          throws STNoSuchPropertyException {
        Property p = (Property) o;
        if ("docString".equals(propertyName)) {
          String docString = jsDocString(p.getDocString());

          List<String> enumValues = p.getType().getEnumValues();
          if (enumValues == null && p.getType().getListElement() != null &&
            p.getType().getListElement().getEnumValues() != null) {
            enumValues = p.getType().getListElement().getEnumValues();
          }
          if (enumValues != null) {
            docString = docString == null ? "" : docString;
            docString += "\n\nPossible values: ";
            for (int i = 0; i < enumValues.size(); i++) {
              docString += enumValues.get(i);
              if (i < enumValues.size() - 1) docString += ", ";
            }
          }

          return docString;

        }

        else if ("jsType".equals(propertyName)) {
          return jsTypeForType(p.getType());
        }

        else if ("listElementEnum".equals(propertyName)) {
          if (p.getType() != null && p.getType().getListElement() != null &&
            p.getType().getListElement().getEnumValues() != null) {
            String enumVals = "";
            int idx = 0;
            for (String val : p.getType().getListElement().getEnumValues()) {
              if (idx != 0) {
                enumVals += ", ";
              }
              enumVals += val;
              idx++;
            }
            return enumVals;
          }
        }

        else if ("listElementKind".equals(propertyName)) {
          if (p.getType().getListElement() != null &&
            p.getType().getListElement().getName() != null) {
            return (packageName + "." + upcase(p.getType().getListElement().toString()));
          }
        }

        else if ("collectionName".equals(propertyName)) {
          return collectionNameForProperty(p);
        }

        else if ("canonicalListElementKind".equals(propertyName)) {
          if (p.getType().getListElement() != null) {

            String collectionModelType = jsTypeForType(p.getType().getListElement());
            Property implied = p.getImpliedProperty();
            if (implied != null) {
              return "function(attrs, options) {\n" +
                "      return new " + collectionModelType + "(\n" +
                "        _(attrs).extend({ " + implied.getName()
                + " : self }), options);\n" +
                "    }";
            }
            else {
              return collectionModelType;
            }
          }
        }

        else if ("defaultValue".equals(propertyName)) {
          String defaultVal = "undefined";
          if (p.isEmbedded()) {
            defaultVal = "new " + jsTypeForType(p.getType()) + "()";
          }
          if (p.getType().getJsonKind().equals(JsonKind.LIST) &&
            jsTypeForType(p.getType().getListElement()).equals("String")) {
            defaultVal = "[]";
            jsTypeForType(p.getType());
          }
          else if (p.getType().getJsonKind().equals(JsonKind.LIST) &&
            p.getType().getListElement().getName() != null) {
            defaultVal = "new " + collectionNameForProperty(p) + "()";
          }
          else if (p.getType().getJsonKind().equals(JsonKind.MAP)) {
            return "{}";
          }
          return defaultVal;
        }

        return super.getProperty(interp, self, o, property, propertyName);
      }
    });

    group.registerModelAdaptor(String.class, new ObjectModelAdaptor() {

      @Override
      public Object getProperty(Interpreter interp, ST self, Object o,
          Object property, String propertyName)
          throws STNoSuchPropertyException {
        final String string = (String) o;
        if ("chunks".equals(propertyName)) {
          /*
           * Split a string into individual chunks that can be reflowed. This implementation is
           * pretty simplistic, but helps make the generated documentation at least somewhat more
           * readable.
           */
          return new Iterator<CharSequence>() {
            int index;
            int length = string.length();
            CharSequence next;

            {
              advance();
            }

            @Override
            public boolean hasNext() {
              return next != null;
            }

            @Override
            public CharSequence next() {
              CharSequence toReturn = next;
              advance();
              return toReturn;
            }

            @Override
            public void remove() {
              throw new UnsupportedOperationException();
            }

            private void advance() {
              int start = advance(false);
              int end = advance(true);
              if (start == end) {
                next = null;
              } else {
                next = string.subSequence(start, end);
              }
            }

            /**
             * Advance to next non-whitespace character.
             */
            private int advance(boolean whitespace) {
              while (index < length
                && (whitespace ^ Character.isWhitespace(string.charAt(index)))) {
                index++;
              }
              return index;
            }
          };
        }
        return super.getProperty(interp, self, o, property, propertyName);
      }
    });

    group.registerModelAdaptor(ApiDescription.class,
        new ObjectModelAdaptor() {
          @Override
          public Object getProperty(Interpreter interp, ST self, Object o,
              Object property, String propertyName)
              throws STNoSuchPropertyException {
            ApiDescription apiDescription = (ApiDescription) o;
            if ("endpoints".equals(propertyName)) {
              Set<EndpointDescription> uniqueEndpoints =
                  new HashSet<EndpointDescription>(apiDescription.getEndpoints());
              List<EndpointDescription> sortedEndpoints = new ArrayList<EndpointDescription>(
                  uniqueEndpoints);
              Collections.sort(sortedEndpoints, new Comparator<EndpointDescription>() {
                @Override
                public int compare(EndpointDescription e1, EndpointDescription e2) {
                  return e1.getPath().compareTo(e2.getPath());
                }
              });
              Iterator<EndpointDescription> iter = sortedEndpoints.iterator();
              while (iter.hasNext()) {
                EndpointDescription ed = iter.next();
                if (ed.getPath() != null && ed.getPath().contains("{path:.*}")) {
                  iter.remove();
                }
              }
              return sortedEndpoints;
            }
            else if ("flatpackEndpoints".equals(propertyName)) {
              List<EndpointDescription> sortedEndpoints = new ArrayList<EndpointDescription>(
                  apiDescription.getEndpoints());
              Collections.sort(sortedEndpoints, new Comparator<EndpointDescription>() {
                @Override
                public int compare(EndpointDescription e1, EndpointDescription e2) {
                  return e1.getPath().compareTo(e2.getPath());
                }
              });
              Iterator<EndpointDescription> iter = sortedEndpoints.iterator();
              while (iter.hasNext()) {
                if (!hasCustomRequestBuilderClass(iter.next())) {
                  iter.remove();
                }
              }
              return sortedEndpoints;
            }
            else if ("requireNames".equals(propertyName)) {
              return entityRequires;
            }
            return super.getProperty(interp, self, o, property, propertyName);
          }
        });

    group.registerModelAdaptor(EndpointDescription.class,
        new ObjectModelAdaptor() {
          @Override
          public Object getProperty(Interpreter interp, ST self, Object o,
              Object property, String propertyName)
              throws STNoSuchPropertyException {
            EndpointDescription end = (EndpointDescription) o;
            if ("docString".equals(propertyName)) {
              return jsDocString(end.getDocString());
            }
            if ("methodName".equals(propertyName)) {

              String path = end.getPath();
              String[] parts = path.split(Pattern.quote("/"));
              StringBuilder sb = new StringBuilder();
              sb.append(end.getMethod().toLowerCase());
              for (int i = 3, j = parts.length; i < j; i++) {
                String part = parts[i];
                if (part.length() == 0) continue;
                if (!part.startsWith("{") && !part.endsWith("}")) {
                  if (part.contains(".")) {
                    String[] dotPart = part.split(Pattern.quote("."));
                    for (String dot : dotPart) {
                      sb.append(upcase(dot));
                    }
                  }
                  else {
                    sb.append(upcase(part));
                  }
                }
                else {
                  sb.append(upcase(part.substring(1, part.length() - 1)));
                }
              }

              return sb.toString();
            }

            else if ("methodParameterList".equals(propertyName)) {
              String path = end.getPath();
              String[] parts = path.split(Pattern.quote("/"));
              StringBuilder sb = new StringBuilder();
              int paramCount = 0;
              for (int i = 3, j = parts.length; i < j; i++) {
                String part = parts[i];
                if (part.length() == 0) continue;

                if (part.startsWith("{") && part.endsWith("}")) {
                  String name = part.substring(1, part.length() - 1);
                  sb.append(name);
                  paramCount++;
                  if (end.getPathParameters() != null
                    && paramCount < end.getPathParameters().size()) {
                    sb.append(", ");
                  }
                }
              }
              if (end.getEntity() != null) {
                if (paramCount > 0) {
                  sb.append(", ");
                }
                sb.append(getNameForType(end.getEntity()));
              }

              return sb.toString();
            }
            else if ("entityName".equals(propertyName)) {
              return getNameForType(end.getEntity());
            }
            else if ("requestBuilderClassName".equals(propertyName)) {

              if (hasCustomRequestBuilderClass(end)) {
                return getBuilderReturnType(end);
              }
              else {
                return "com.getperka.flatpack.client.JsonRequest";
              }
            }

            else if ("requestBuilderBlockName".equals(propertyName)) {
              return getBuilderReturnType(end) + "Block";
            }

            else if ("pathDecoded".equals(propertyName)) {
              // URL-decode the path in the endpoint description
              try {
                String decoded = URLDecoder.decode(end.getPath(), "UTF8");
                return decoded;
              } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
              }
            }
            return super.getProperty(interp, self, o, property, propertyName);
          }

        });

    group.registerModelAdaptor(ParameterDescription.class,
        new ObjectModelAdaptor() {
          @Override
          public Object getProperty(Interpreter interp, ST self, Object o,
              Object property, String propertyName)
              throws STNoSuchPropertyException {
            ParameterDescription param = (ParameterDescription) o;
            if ("requireName".equals(propertyName)) {
              return upcase(param.getName());
            }
            else if ("docString".equals(propertyName)) {
              return jsDocString(param.getDocString());
            }
            return super.getProperty(interp, self, o, property, propertyName);
          }
        });

    Map<String, Object> namesMap = new HashMap<String, Object>();
    namesMap.put("packageName", packageName);
    group.defineDictionary("names", namesMap);

    return group;
  }

  private void render(ST enumST, File packageDir, String fileName)
      throws IOException {

    if (!packageDir.isDirectory() && !packageDir.mkdirs()) {
      logger
          .error("Could not create output directory {}", packageDir.getPath());
      return;
    }
    Writer fileWriter = new OutputStreamWriter(new FileOutputStream(new File(
        packageDir, fileName)), "UTF8");
    AutoIndentWriter writer = new AutoIndentWriter(fileWriter);
    writer.setLineWidth(80);
    enumST.write(writer);
    fileWriter.close();
  }
}
TOP

Related Classes of com.getperka.flatpack.fast.JavaScriptDialect

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.