Package com.github.sommeri.less4j.core.validators

Source Code of com.github.sommeri.less4j.core.validators.LessAstValidator

package com.github.sommeri.less4j.core.validators;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.github.sommeri.less4j.core.ast.ASTCssNode;
import com.github.sommeri.less4j.core.ast.ASTCssNodeType;
import com.github.sommeri.less4j.core.ast.AbstractVariableDeclaration;
import com.github.sommeri.less4j.core.ast.Body;
import com.github.sommeri.less4j.core.ast.DetachedRuleset;
import com.github.sommeri.less4j.core.ast.EscapedSelector;
import com.github.sommeri.less4j.core.ast.FaultyExpression;
import com.github.sommeri.less4j.core.ast.MixinReference;
import com.github.sommeri.less4j.core.ast.NestedSelectorAppender;
import com.github.sommeri.less4j.core.ast.PseudoClass;
import com.github.sommeri.less4j.core.ast.RuleSet;
import com.github.sommeri.less4j.core.ast.Selector;
import com.github.sommeri.less4j.core.ast.SupportsLogicalCondition;
import com.github.sommeri.less4j.core.ast.SupportsLogicalOperator;
import com.github.sommeri.less4j.core.ast.Variable;
import com.github.sommeri.less4j.core.compiler.stages.ASTManipulator;
import com.github.sommeri.less4j.core.problems.ProblemsHandler;

public class LessAstValidator {

  private final ProblemsHandler problemsHandler;
  private final ASTManipulator manipulator = new ASTManipulator();
  private final SupportedLessBodyMembers allowedBodyMembers = new SupportedLessBodyMembers();

  public LessAstValidator(ProblemsHandler problemsHandler) {
    this.problemsHandler = problemsHandler;
  }

  public void validate(ASTCssNode node) {
    switch (node.getType()) {
    case RULE_SET: {
      checkEmptySelector((RuleSet) node);
      checkTopLevelNested((RuleSet) node);
      break;
    }
    case MIXIN_REFERENCE: {
      checkInterpolatedNamespaceName((MixinReference) node);
      checkInterpolatedMixinName((MixinReference) node);
      break;
    }
    case PSEUDO_CLASS: {
      checkDeprecatedParameterType((PseudoClass) node);
      break;
    }
    case ESCAPED_SELECTOR: {
      problemsHandler.deprecatedSyntaxEscapedSelector((EscapedSelector) node);
      break;
    }
    case GENERAL_BODY: {
      checkForDisallowedMembers((Body) node);
      break;
    }
    case SUPPORTS_CONDITION_LOGICAL: {
      checkForLogicalConditionConsistency((SupportsLogicalCondition) node);
      break;
    }
    case DETACHED_RULESET: {
      checkInapropriateLocation((DetachedRuleset) node);
      break;
    }
    default:
      //nothing is needed
    }

    List<ASTCssNode> childs = new ArrayList<ASTCssNode>(node.getChilds());
    for (ASTCssNode kid : childs) {
      validate(kid);
    }

  }

  private void checkInapropriateLocation(DetachedRuleset detachedRuleset) {
    ASTCssNode parent = detachedRuleset.getParent();
    if (!isVariableDeclaration(parent) && !isMixinReference(parent)) {
      manipulator.replace(detachedRuleset, new FaultyExpression(detachedRuleset));
      problemsHandler.wrongDetachedRulesetLocation(detachedRuleset);
    }
  }

  private boolean isMixinReference(ASTCssNode parent) {
    return parent.getType() == ASTCssNodeType.MIXIN_REFERENCE;
  }

  private boolean isVariableDeclaration(ASTCssNode parent) {
    return parent instanceof AbstractVariableDeclaration;
  }

  private void checkForLogicalConditionConsistency(SupportsLogicalCondition condition) {
    Iterator<SupportsLogicalOperator> logicalOperators = condition.getLogicalOperators().iterator();
    if (!logicalOperators.hasNext())
      return;

    SupportsLogicalOperator masterOperator = logicalOperators.next();
    while (logicalOperators.hasNext()) {
      SupportsLogicalOperator operator = logicalOperators.next();
      if (!masterOperator.getOperator().equals(operator.getOperator()))
        problemsHandler.warnInconsistentSupportsLogicalConditionOperators(operator, masterOperator);
    }
  }

  private void checkTopLevelNested(RuleSet node) {
    if (node.getParent().getType() != ASTCssNodeType.STYLE_SHEET)
      return;

    for (Selector selector : node.getSelectors()) {
      NestedSelectorAppender appender = selector.findFirstAppender();
      if (appender != null) {
        problemsHandler.nestedAppenderOnTopLevel(appender);
        manipulator.removeFromClosestBody(node);
        return;
      }
    }

  }

  private void checkForDisallowedMembers(Body body) {
    Set<ASTCssNodeType> supportedMembers = allowedBodyMembers.getSupportedMembers(body);
    for (ASTCssNode member : body.getMembers()) {
      ASTCssNodeType type = member.getType();
      if (!supportedMembers.contains(type))
        problemsHandler.wrongMemberInLessBody(member, body);
    }
  }

  private void checkInterpolatedMixinName(MixinReference reference) {
    if (reference.hasInterpolatedFinalName()) {
      problemsHandler.interpolatedMixinReferenceSelector(reference);
      manipulator.removeFromClosestBody(reference);
    }
  }

  private void checkInterpolatedNamespaceName(MixinReference reference) {
    if (reference.hasInterpolatedNameChain()) {
      problemsHandler.interpolatedNamespaceReferenceSelector(reference);
      manipulator.removeFromClosestBody(reference);
    }
  }

  private void checkDeprecatedParameterType(PseudoClass pseudo) {
    ASTCssNode parameter = pseudo.getParameter();
    if (parameter == null || parameter.getType() != ASTCssNodeType.VARIABLE)
      return;
   
    Variable variable = (Variable) parameter;
    if (!variable.hasInterpolatedForm())
      problemsHandler.variableAsPseudoclassParameter(pseudo);
  }

  private void checkEmptySelector(RuleSet ruleSet) {
    if (ruleSet.getSelectors() == null || ruleSet.getSelectors().isEmpty())
      problemsHandler.rulesetWithoutSelector(ruleSet);
  }

}
TOP

Related Classes of com.github.sommeri.less4j.core.validators.LessAstValidator

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.