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

com.google.template.soy.conformance.ValidatedConformanceConfig Maven / Gradle / Ivy

There is a newer version: 2024-02-26
Show newest version
/*
 * Copyright 2017 Google 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.
 */

package com.google.template.soy.conformance;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.escape.Escaper;
import com.google.common.escape.Escapers;
import com.google.template.soy.basetree.Node;
import com.google.template.soy.conformance.Requirement.RequirementTypeCase;
import com.google.template.soy.error.ErrorReporter;
import com.google.template.soy.error.SoyErrorKind;
import com.google.template.soy.error.SoyErrorKind.StyleAllowance;
import java.lang.reflect.Constructor;

/** A validated wrapper for {@link ConformanceConfig}. */
public final class ValidatedConformanceConfig {
  /** An empty configuration. */
  public static final ValidatedConformanceConfig EMPTY =
      new ValidatedConformanceConfig(ImmutableList.of());

  private static final Escaper MESSAGE_FORMAT =
      Escapers.builder().addEscape('{', "'{").addEscape('}', "}'").build();

  /**
   * Creates a validated configuration object.
   *
   * @throws IllegalArgumentException if there is an error in the config object.
   */
  public static ValidatedConformanceConfig create(ConformanceConfig config) {
    ImmutableList.Builder rulesBuilder = new ImmutableList.Builder<>();
    for (Requirement requirement : config.getRequirementList()) {
      Preconditions.checkArgument(
          !requirement.getErrorMessage().isEmpty(), "requirement missing error message");
      Preconditions.checkArgument(
          requirement.getRequirementTypeCase() != RequirementTypeCase.REQUIREMENTTYPE_NOT_SET,
          "requirement missing type");
      Rule rule = forRequirement(requirement);
      ImmutableList whitelists = ImmutableList.copyOf(requirement.getWhitelistList());
      rulesBuilder.add(RuleWithWhitelists.create(rule, whitelists));
    }
    return new ValidatedConformanceConfig(rulesBuilder.build());
  }

  private final ImmutableList rules;

  private ValidatedConformanceConfig(ImmutableList rules) {
    this.rules = rules;
  }

  ImmutableList getRules() {
    return rules;
  }

  private static Rule forRequirement(Requirement requirement) {
    SoyErrorKind error =
        SoyErrorKind.of(
            MESSAGE_FORMAT.escape(requirement.getErrorMessage()), StyleAllowance.values());
    switch (requirement.getRequirementTypeCase()) {
      case CUSTOM:
        return createCustomRule(requirement.getCustom().getJavaClass(), error);
      case BANNED_CSS_SELECTOR:
        Requirement.BannedCssSelector bannedCss = requirement.getBannedCssSelector();
        return new BannedCssSelector(ImmutableSet.copyOf(bannedCss.getSelectorList()), error);
      case BANNED_DIRECTIVE:
        Requirement.BannedDirective bannedDirective = requirement.getBannedDirective();
        return new BannedDirective(ImmutableSet.copyOf(bannedDirective.getDirectiveList()), error);
      case BANNED_FUNCTION:
        Requirement.BannedFunction bannedFunction = requirement.getBannedFunction();
        return new BannedFunction(ImmutableSet.copyOf(bannedFunction.getFunctionList()), error);
      case BANNED_RAW_TEXT:
        Requirement.BannedRawText bannedRawText = requirement.getBannedRawText();
        return new BannedRawText(ImmutableSet.copyOf(bannedRawText.getTextList()), error);
      case BANNED_HTML_TAG:
        Requirement.BannedHtmlTag bannedHtmlTag = requirement.getBannedHtmlTag();
        return new BannedHtmlTag(bannedHtmlTag.getTagList(), error);
      case REQUIRE_STRICT_AUTOESCAPING:
        return new RequireStrictAutoescaping(error);
      case REQUIRE_STRONGLY_TYPED_IJ_PARAMS:
        return new RequireStronglyTypedIjParams(error);
      case REQUIREMENTTYPE_NOT_SET:
      default:
        throw new AssertionError(
            "unexpected requirement type: " + requirement.getRequirementTypeCase());
    }
  }

  /**
   * Instantiates a custom conformance check from its fully-qualified class name, specified in the
   * conformance protobuf.
   *
   * 

Custom conformance checks must extend {@link Rule}. They must also have a binary constructor * with {@link ErrorReporter} and {@link SoyErrorKind} parameters. */ private static Rule createCustomRule(String javaClass, SoyErrorKind error) { Class> customRuleClass; try { @SuppressWarnings("unchecked") Class> asSubclass = (Class>) Class.forName(javaClass).asSubclass(Rule.class); customRuleClass = asSubclass; } catch (ClassNotFoundException e) { throw new IllegalArgumentException("custom rule class " + javaClass + " not found", e); } try { // It is ok for the constructor to be non-public as long as it is defined in this package // if it is non public and defined in another package, this will throw an // IllegalAccessException which seems about right. Constructor> ctor = customRuleClass.getDeclaredConstructor(SoyErrorKind.class); return ctor.newInstance(error); } catch (ReflectiveOperationException e) { throw new IllegalArgumentException( "unable to construct custom rule class: " + javaClass + ": " + e.getMessage(), e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy