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

com.google.javascript.jscomp.deps.DepsFileRegexParser Maven / Gradle / Ivy

/*
 * Copyright 2008 The Closure Compiler Authors.
 *
 * 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.javascript.jscomp.deps;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import com.google.javascript.jscomp.ErrorManager;
import com.google.javascript.jscomp.deps.DependencyInfo.Require;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A parser that can extract dependency information from existing deps.js files.
 *
 * 

See //javascript/closure/deps.js for an example file. */ @GwtIncompatible("java.util.regex") public final class DepsFileRegexParser extends JsFileLineParser { private static final Logger logger = Logger.getLogger(DepsFileRegexParser.class.getName()); /** * Pattern for matching JavaScript string literals. The group is: * goog.addDependency({1}); */ private final Matcher depMatcher = Pattern.compile("\\s*goog.addDependency\\((.*)\\);?\\s*").matcher(""); /** * Pattern for matching the args of a goog.addDependency(). The group is: * goog.addDependency({1}, {2}, {3}, {4?}); */ private final Matcher depArgsMatch = Pattern.compile( "\\s*([^,]*), (\\[[^\\]]*\\]), (\\[[^\\]]*\\])" + "(?:, (true|false|\\{[^{}]*\\}))?\\s*") .matcher(""); /** * The dependency information extracted from the current file. */ private List depInfos; /** Translates paths in different build systems. */ private final Function pathTranslator; /** * Constructor * * @param errorManager Handles parse errors. */ public DepsFileRegexParser(ErrorManager errorManager) { this(Functions.identity(), errorManager); } /** * @param pathTranslator Translates paths in different build systems. * @param errorManager Handles parse errors. */ public DepsFileRegexParser(Function pathTranslator, ErrorManager errorManager) { super(errorManager); this.pathTranslator = pathTranslator; } /** * Parses the given file and returns a list of dependency information that it * contained. * * @param filePath Path to the file to parse. * @return A list of DependencyInfo objects. * @throws IOException Thrown if the file could not be read. */ public List parseFile(String filePath) throws IOException { return parseFileReader(filePath, Files.newReader(new File(filePath), UTF_8)); } /** * Parses the given file and returns a list of dependency information that it * contained. * It uses the passed in fileContents instead of reading the file. * * @param filePath Path to the file to parse. * @param fileContents The contents to parse. * @return A list of DependencyInfo objects. */ public List parseFile(String filePath, String fileContents) { return parseFileReader(filePath, new StringReader(fileContents)); } /** * Parses the file from the given reader and returns a list of * dependency information that it contained. * * @param filePath Path to the file to parse. * @param reader A reader for the file. * @return A list of DependencyInfo objects. */ public List parseFileReader(String filePath, Reader reader) { depInfos = new ArrayList<>(); if (logger.isLoggable(Level.FINE)) { logger.fine("Parsing Dep: " + filePath); } doParse(filePath, reader); return depInfos; } /** * Extracts dependency information from lines that look like * goog.addDependency('pathRelativeToClosure', ['provides'], ['requires']); * Adds the dependencies to depInfos. * * @throws ParseException Thrown if the given line has a malformed * goog.addDependency(). */ @Override protected boolean parseLine(String line) throws ParseException { boolean hasDependencies = false; // Quick check that will catch most cases. This is a performance win for teams with a lot of JS. if (line.contains("addDependency")) { depMatcher.reset(line); // See if the line looks like: goog.addDependency(...) if (depMatcher.matches()) { hasDependencies = true; String addDependencyParams = depMatcher.group(1); depArgsMatch.reset(addDependencyParams); // Extract the three parameters. if (!depArgsMatch.matches()) { // Although we could recover, we mark this as fatal since there should // not be problems with generated deps.js files. throw new ParseException("Invalid arguments to goog.addDependency(). Found: " + addDependencyParams, true); } // Parse the file path. String relativePath = parseJsString(depArgsMatch.group(1)); String path = pathTranslator.apply(relativePath); List provides = parseJsStringArray(depArgsMatch.group(2)); Map loadFlags = parseLoadFlags(depArgsMatch.group(4)); // ES6 modules are require'd by path but do not provide them in the addDependency call. if ("es6".equals(loadFlags.get("module"))) { provides.add(relativePath); } DependencyInfo depInfo = SimpleDependencyInfo.builder(path, filePath) .setProvides(provides) .setRequires( parseJsStringArray(depArgsMatch.group(3)) .stream() .map(Require::parsedFromDeps) .collect(toImmutableList())) .setLoadFlags(loadFlags) .build(); if (logger.isLoggable(Level.FINE)) { logger.fine("Found dep: " + depInfo); } depInfos.add(depInfo); } } return !shortcutMode || hasDependencies || CharMatcher.whitespace().matchesAllOf(line); } private Map parseLoadFlags(String loadFlags) throws ParseException { if (loadFlags == null || loadFlags.equals("false")) { return ImmutableMap.of(); } else if (loadFlags.equals("true")) { return ImmutableMap.of("module", "goog"); } else { return parseJsStringMap(loadFlags); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy