org.daisy.pipeline.css.sass.impl.SassAnalyzer Maven / Gradle / Ivy
The newest version!
package org.daisy.pipeline.css.sass.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import com.google.common.collect.Iterables;
import com.google.common.io.CharStreams;
import cz.vutbr.web.css.NetworkProcessor;
import cz.vutbr.web.csskit.DefaultNetworkProcessor;
import cz.vutbr.web.csskit.antlr.CSSSource;
import cz.vutbr.web.csskit.antlr.CSSSourceReader;
import cz.vutbr.web.csskit.antlr.DefaultCSSSourceReader;
import cz.vutbr.web.domassign.GenericTreeWalker;
import cz.vutbr.web.csskit.antlr.CSSSourceReader.CSSInputStream;
import org.antlr.runtime.ANTLRReaderStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.daisy.common.file.URLs;
import org.daisy.pipeline.css.Medium;
import org.daisy.pipeline.datatypes.DatatypeRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class SassAnalyzer {
private static final Logger logger = LoggerFactory.getLogger(SassAnalyzer.class.getName());
private final Collection media;
private final CSSSourceReader cssReader;
final DatatypeRegistry datatypes; // also used in SassDocumentationParser
public SassAnalyzer(Collection media, URIResolver uriResolver, DatatypeRegistry datatypes) {
this.media = media;
this.datatypes = datatypes;
NetworkProcessor network = new DefaultNetworkProcessor() {
@Override
public Reader fetch(URL url, Charset encoding, boolean forceEncoding, boolean assertEncoding)
throws IOException {
logger.debug("Fetching style sheet: " + url);
if (uriResolver != null) {
Source resolved; {
try {
resolved = uriResolver.resolve(URLs.asURI(url).toASCIIString(), ""); }
catch (TransformerException e) {
throw new IOException(e); }}
if (resolved != null) {
if (resolved instanceof StreamSource) {
InputStreamReader r = detectEncodingAndSkipBOM(
((StreamSource)resolved).getInputStream(), null, encoding, forceEncoding);
if (assertEncoding) {
if (encoding == null)
throw new IllegalArgumentException("encoding must not be null");
if (!encoding.equals(getEncoding(r)))
throw new IOException("Failed to read URL as " + encoding + ": " + url);
}
return r;
} else {
url = new URL(resolved.getSystemId());
}
}
}
return super.fetch(url, encoding, forceEncoding, assertEncoding);
}
};
cssReader = new DefaultCSSSourceReader(network) {
@Override
public boolean supportsMediaType(String mediaType, URL url) {
if ("text/css".equals(mediaType) || "text/x-scss".equals(mediaType))
return true;
else if (mediaType == null
&& (url == null || url.toString().endsWith(".css") || url.toString().endsWith(".scss")))
return true;
else
return false;
}
// the returned CSSInputStream contains the original (unprocessed) file
@Override
public CSSInputStream read(CSSSource source) throws IOException {
if (source.type == CSSSource.SourceType.URL) {
URL url = (URL)source.source;
if (url != null && !url.toString().endsWith(".css") && !url.toString().endsWith(".scss"))
// check whether the resource exists when ".scss" is added
try {
return read(new CSSSource(new URL(url.toString() + ".scss"), source.encoding, source.mediaType));
} catch (IOException e) {
// ... or ".css" is added
try {
return read(new CSSSource(new URL(url.toString() + ".css"), source.encoding, source.mediaType));
} catch (IOException ee) {
}
// ... or "_" and ".scss" are added
try {
String fileName = url.toString();
fileName = fileName.substring(fileName.lastIndexOf('/') + 1, fileName.length());
return read(new CSSSource(URLs.asURL(URLs.asURI(url).resolve("_" + fileName + ".scss")),
source.encoding,
source.mediaType));
} catch (IOException ee) {
}
// ... or "_index.scss" is added
try {
return read(new CSSSource(new URL(url.toString() + "/_index.scss"), source.encoding, source.mediaType));
} catch (IOException ee) {
}
// otherwise fail
throw e;
}
if (uriResolver != null) {
try {
// NetworkProcessor.fetch() also does resolve() but we need an additional resolve() to give
// CSSInputStream the correct base URL
Source resolved = uriResolver.resolve(URLs.asURI(url).toASCIIString(), "");
if (resolved != null)
source = new CSSSource(new URL(resolved.getSystemId()), source.encoding, source.mediaType);
} catch (TransformerException e) {
throw new IOException(e);
}
}
}
return super.read(source);
}
};
}
public Collection getVariableDeclarations(Iterable