Package com.github.sommeri.less4j.core.compiler.selectors

Source Code of com.github.sommeri.less4j.core.compiler.selectors.SelectorsManipulator

package com.github.sommeri.less4j.core.compiler.selectors;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import com.github.sommeri.less4j.core.ast.ElementSubsequent;
import com.github.sommeri.less4j.core.ast.Extend;
import com.github.sommeri.less4j.core.ast.NestedSelectorAppender;
import com.github.sommeri.less4j.core.ast.Selector;
import com.github.sommeri.less4j.core.ast.SelectorCombinator;
import com.github.sommeri.less4j.core.ast.SelectorPart;
import com.github.sommeri.less4j.core.problems.BugHappened;
import com.github.sommeri.less4j.utils.ArraysUtils;

public class SelectorsManipulator {

  public List<Selector> replaceAppenders(Selector inSelector, List<Selector> replacements) {
    if (!inSelector.containsAppender()) {
      return indirectJoinAll(replacements, null, inSelector);
    }

    List<Selector> result = Arrays.asList(inSelector);
    while (result.get(0).containsAppender()) {
      List<Selector> nextRound = new ArrayList<Selector>();
      for (Selector tbch : result) {
        nextRound.addAll(replaceFirstAppender(tbch, replacements));
      }

      result = nextRound;
    }

    return result;
  }

  private List<Selector> indirectJoinAll(List<Selector> first, SelectorCombinator combinator, Selector second) {
    List<Selector> result = new ArrayList<Selector>();
    for (Selector previous : first) {
      result.add(indirectJoin(previous, combinator, second));
    }

    return result;
  }

  public Selector indirectJoin(Selector firstI, SelectorCombinator combinator, Selector secondI) {
    // if both of them are null, something is very wrong
    if (secondI == null)
      return firstI.clone();

    if (firstI == null)
      return secondI.clone();

    Selector first = firstI.clone();
    Selector second = secondI.clone();

    return indirectJoinNoClone(first, combinator, second);
  }

  public Selector indirectJoinNoClone(Selector first, SelectorCombinator combinator, Selector second) {
    return indirectJoinNoClone(first, combinator, second.getParts(), second.getExtend());
  }

  public Selector indirectJoinNoClone(Selector first, SelectorCombinator combinator, List<SelectorPart> second, List<Extend> extend) {
    first.addExtends(extend);
   
    if (second.isEmpty())
      return first;

    if (combinator != null) {
      second.get(0).setLeadingCombinator(combinator);
    }
    first.addParts(second);
    first.configureParentToAllChilds();

    return first;
  }

  public Selector directJoin(Selector firstI, Selector secondI) {
    // if both of them are null, something is very wrong
    if (secondI == null)
      return firstI.clone();

    if (firstI == null)
      return secondI.clone();

    Selector first = firstI.clone();
    List<SelectorPart> secondParts = ArraysUtils.deeplyClonedList(secondI.getParts());
    List<Extend> secondExtends = ArraysUtils.deeplyClonedList(secondI.getExtend());
    SelectorPart secondHead = secondParts.get(0);

    if (secondHead.isAppender())
      return indirectJoinNoClone(first, secondHead.getLeadingCombinator(), secondParts, secondExtends);

    /*
     * FIXME: test on old whether survives if first is not simple selector. (say, if:
     * (~"escaped") {
     *   &:pseudo() {
     *   }
     * }
     *
     */
    SelectorPart attachToHead = first.getLastPart();
    directlyJoinParts(attachToHead, secondHead);

    secondParts.remove(0);
    SelectorCombinator leadingCombinator = secondParts.isEmpty() ? null : secondParts.get(0).getLeadingCombinator();
    return indirectJoinNoClone(first, leadingCombinator, secondParts, secondExtends);
  }

  public void directlyJoinParts(SelectorPart first, SelectorPart second) {
    if (second.hasElement()) {
      String secondName = second.hasElement() ? second.getElementName().getName() : "";
      if (first.hasSubsequent()) {
        ElementSubsequent subsequent = first.getLastSubsequent();
        subsequent.extendName(secondName);
      } else {
        first.extendName(secondName, second.getUnderlyingStructure());
      }
    }

    first.addSubsequent(second.getSubsequent());
    first.configureParentToAllChilds();
  }

  private Collection<Selector> replaceFirstAppender(Selector selector, List<Selector> previousSelectors) {
    if (selector.getHead().isAppender()) {
      NestedSelectorAppender appender = (NestedSelectorAppender) selector.getHead();
      return joinAll(previousSelectors, chopOffHead(selector), appender.getLeadingCombinator(), appender.isDirectlyBefore());
    }

    // appender somewhere in the middle
    NestedSelectorAppender appender = selector.findFirstAppender();
    if (appender == null)
      throw new BugHappened("This is very weird error and should not happen.", selector);

    Selector afterAppender = splitOn(selector, appender);
    List<Selector> partialResults = joinAll(selector, previousSelectors, appender.getLeadingCombinator(), appender.isDirectlyAfter());
    return joinAll(partialResults, afterAppender, null, appender.isDirectlyBefore());
  }

  private List<Selector> joinAll(Selector first, List<Selector> seconds, SelectorCombinator leadingCombinator, boolean appenderDirectlyPlaced) {
    //pretending null as after appender, less.js does not handle this case anyway
    //this case being:
    //.input-group-addon + {
    //  .selector {
    //    heeej: hoou;
    //  }
    //}
    boolean directJoin = isDirect(leadingCombinator, appenderDirectlyPlaced, null);
    if (directJoin)
      return directJoinAll(first, seconds);
    else
      return indirectJoinAll(leadingCombinator, first, seconds);
  }

  private List<Selector> joinAll(List<Selector> firsts, Selector second, SelectorCombinator beforeAppenderCombinator, boolean appenderDirectlyPlaced) {
    boolean directJoin = isDirect(beforeAppenderCombinator, appenderDirectlyPlaced, second);
    if (directJoin)
      return directJoinAll(firsts, second);
    else
      return indirectJoinAll(firsts, beforeAppenderCombinator, second);
  }

  private Selector chopOffHead(Selector selector) {
    if (!selector.isCombined())
      return null;

    selector.removeHead();
    return selector;
  }

  private List<Selector> directJoinAll(List<Selector> firsts, Selector second) {
    List<Selector> result = new ArrayList<Selector>();
    for (Selector first : firsts) {
      result.add(directJoin(first, second));
    }

    return result;
  }

  private List<Selector> indirectJoinAll(SelectorCombinator leadingCombinator, Selector first, List<Selector> seconds) {
    List<Selector> result = new ArrayList<Selector>();
    for (Selector second : seconds) {
      result.add(indirectJoin(first, leadingCombinator, second));
    }

    return result;
  }

  private List<Selector> directJoinAll(Selector first, List<Selector> seconds) {
    List<Selector> result = new ArrayList<Selector>();
    for (Selector second : seconds) {
      result.add(directJoin(first, second));
    }

    return result;
  }

  private boolean isDirect(SelectorCombinator beforeAppenderCombinator, boolean appenderDirectlyPlaced, Selector afterAppender) {
    return beforeAppenderCombinator == null && appenderDirectlyPlaced && (afterAppender == null || !afterAppender.hasLeadingCombinator());
  }

  private Selector splitOn(Selector selector, NestedSelectorAppender appender) {
    List<SelectorPart> parts = selector.getParts();
    int indexOfAppender = parts.indexOf(appender);
    List<SelectorPart> appenderAndAfter = parts.subList(indexOfAppender, parts.size());

    //remove appender
    appenderAndAfter.remove(0);
    appender.setParent(null);

    //create selector with after appender parts
    Selector result = null;
    if (!appenderAndAfter.isEmpty()) {
      result = new Selector(selector.getUnderlyingStructure(), new ArrayList<SelectorPart>(appenderAndAfter));
      result.configureParentToAllChilds();
    }

    //leave only before appender parts in original selector
    appenderAndAfter.clear();
    return result;
  }

}
TOP

Related Classes of com.github.sommeri.less4j.core.compiler.selectors.SelectorsManipulator

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.