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

Source Code of com.github.sommeri.less4j.core.compiler.stages.SingleImportSolver

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

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.github.sommeri.less4j.LessSource;
import com.github.sommeri.less4j.LessCompiler.Configuration;
import com.github.sommeri.less4j.LessSource.CannotReadFile;
import com.github.sommeri.less4j.LessSource.FileNotFound;
import com.github.sommeri.less4j.LessSource.StringSourceException;
import com.github.sommeri.less4j.core.ast.ASTCssNode;
import com.github.sommeri.less4j.core.ast.ASTCssNodeType;
import com.github.sommeri.less4j.core.ast.FaultyNode;
import com.github.sommeri.less4j.core.ast.GeneralBody;
import com.github.sommeri.less4j.core.ast.Import;
import com.github.sommeri.less4j.core.ast.Import.ImportContent;
import com.github.sommeri.less4j.core.ast.InlineContent;
import com.github.sommeri.less4j.core.ast.Import.ImportMultiplicity;
import com.github.sommeri.less4j.core.ast.Media;
import com.github.sommeri.less4j.core.ast.StyleSheet;
import com.github.sommeri.less4j.core.compiler.expressions.TypesConversionUtils;
import com.github.sommeri.less4j.core.parser.ANTLRParser;
import com.github.sommeri.less4j.core.parser.ASTBuilder;
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
import com.github.sommeri.less4j.core.problems.ProblemsHandler;

public class SingleImportSolver {

  private final ProblemsHandler problemsHandler;
  private final Configuration configuration;
  private TypesConversionUtils conversionUtils = new TypesConversionUtils();
  private ASTManipulator astManipulator = new ASTManipulator();

  private Set<LessSource> importedSources = new HashSet<LessSource>();

  public SingleImportSolver(ProblemsHandler problemsHandler, Configuration configuration) {
    this.problemsHandler = problemsHandler;
    this.configuration = configuration;
  }

  public void solveImports(StyleSheet node, LessSource source) {
    doSolveImports(node, source);
  }

  private void doSolveImports(StyleSheet node, LessSource source) {
    List<ASTCssNode> childs = new ArrayList<ASTCssNode>(node.getChilds());
    for (ASTCssNode kid : childs) {
      if (kid.getType() == ASTCssNodeType.IMPORT) {
        importEncountered((Import) kid, source);
      }
    }
  }

  public ASTCssNode importEncountered(Import node, LessSource source) {
    String filename = conversionUtils.extractFilename(node.getUrlExpression(), problemsHandler, configuration);
    if (filename == null) {
      problemsHandler.errorWrongImport(node.getUrlExpression());
      return null;
    }
    String urlParams = "";
    int paramsIndx = filename.lastIndexOf("?");
    if (paramsIndx != -1) {
      urlParams = filename.substring(paramsIndx);
      filename = filename.substring(0, paramsIndx);
    }

    // css file imports should be left as they are
    // FIXME ! they should be relativized
    if (treatAsCss(node, filename))
      return null;

    filename = addLessSuffixIfNeeded(filename, urlParams);
    LessSource importedSource;
    try {
      importedSource = source.relativeSource(filename);
    } catch (FileNotFound ex) {
      problemsHandler.errorFileNotFound(node, filename);
      return null;
    } catch (CannotReadFile e) {
      problemsHandler.errorFileCanNotBeRead(node, filename);
      return null;
    } catch (StringSourceException ex) {
      // imports are relative to current file and we do not know its location
      problemsHandler.warnLessImportNoBaseDirectory(node.getUrlExpression());
      return null;
    }

    // import once should not import a file that was already imported
    if (isImportOnce(node) && alreadyVisited(importedSource)) {
      astManipulator.removeFromBody(node);
      return null;
    }
    importedSources.add(importedSource);

    String importedContent;
    try {
      importedContent = importedSource.getContent();
    } catch (FileNotFound e) {
      problemsHandler.errorFileNotFound(node, filename);
      return null;
    } catch (CannotReadFile e) {
      problemsHandler.errorFileCanNotBeRead(node, filename);
      return null;
    }

    if (node.isInline()) {
      HiddenTokenAwareTree underlyingStructure = node.getUnderlyingStructure();
      StyleSheet result = new StyleSheet(underlyingStructure);
      InlineContent content = new InlineContent(underlyingStructure, importedContent);
      result.addMember(content);
      result.configureParentToAllChilds();
     
      astManipulator.replaceInBody(node, content);
      return result;
    }
   
    StyleSheet importedAst = buildImportedAst(node, importedSource, importedContent);
    if (node.isReferenceOnly() || node.isSilent()) {
      astManipulator.setTreeSilentness(importedAst, true);
    }
    astManipulator.replaceInBody(node, importedAst.getChilds());
    return importedAst;
  }

  private StyleSheet buildImportedAst(Import node, LessSource source, String content) {
    // parse imported file
    StyleSheet importedAst = parseContent(node, content, source);

    // add media queries if needed
    if (node.hasMediums()) {
      HiddenTokenAwareTree underlyingStructure = node.getUnderlyingStructure();
      StyleSheet result = new StyleSheet(underlyingStructure);
      Media media = new Media(underlyingStructure);
      result.addMember(media);
      media.setParent(result);
      media.setMediums(node.getMediums());
      GeneralBody mediaBody = new GeneralBody(underlyingStructure, importedAst.getMembers());
      media.setBody(mediaBody);
      media.configureParentToAllChilds();
      mediaBody.configureParentToAllChilds();
      return result;
    }
   
    return importedAst;
  }

  private boolean isImportOnce(Import node) {
    return node.getMultiplicity() == ImportMultiplicity.IMPORT
            || node.getMultiplicity() == ImportMultiplicity.IMPORT_ONCE;
  }

  private boolean alreadyVisited(LessSource importedSource) {
    return importedSources.contains(importedSource);
  }
 
  public Set<LessSource> getImportedSources() {
    return importedSources;
  }

  private StyleSheet parseContent(Import importNode, String importedContent, LessSource source) {
    ANTLRParser parser = new ANTLRParser();
    ANTLRParser.ParseResult parsedSheet = parser.parseStyleSheet(importedContent, source);
    if (parsedSheet.hasErrors()) {
      StyleSheet result = new StyleSheet(importNode.getUnderlyingStructure());
      result.addMember(new FaultyNode(importNode));
      problemsHandler.addErrors(parsedSheet.getErrors());
      return result;
    }
    ASTBuilder astBuilder = new ASTBuilder(problemsHandler);
    StyleSheet lessStyleSheet = astBuilder.parse(parsedSheet.getTree());
    return lessStyleSheet;

  }

  private String addLessSuffixIfNeeded(String filename, String urlParams) {
    if ((new File(filename)).getName().contains("."))
      return filename;

    return filename + ".less" + urlParams;
  }

  private boolean treatAsCss(Import node, String filename) {
    ImportContent contentKind = node.getContentKind();
    return contentKind==ImportContent.CSS || (contentKind==ImportContent.SUFFIX_BASED && isCssFile(filename));
  }

  private boolean isCssFile(String filename) {
    String lowerCase = filename.toLowerCase();
    return lowerCase.endsWith(".css") || lowerCase.endsWith("/css");
  }

}
TOP

Related Classes of com.github.sommeri.less4j.core.compiler.stages.SingleImportSolver

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.