Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit a3c6236efa8e60b44cfb548114eae80424b11023 0 parents
@nzakas authored
30 README
@@ -0,0 +1,30 @@
+Combiner
+Copyright (c) 2009 Nicholas C. Zakas. All rights reserved.
+
+-------------------------------------------------------------------------------
+ About
+-------------------------------------------------------------------------------
+
+http://www.nczonline.net/blog/2009/09/22/introducing-combiner-a-javascriptcss-concatenation-tool/
+
+-------------------------------------------------------------------------------
+ License
+-------------------------------------------------------------------------------
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
8 ant.properties
@@ -0,0 +1,8 @@
+src.dir = src
+lib.dir = lib
+doc.dir = doc
+build.dir = build
+product.name = combiner
+version.number = 0.0.1
+jar.name = ${product.name}-${version.number}.jar
+dist.package.name = ${product.name}-${version.number}
62 build.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<project name="Combiner" default="build.jar" basedir=".">
+
+ <target name="clean" depends="-load.properties">
+ <delete dir="${build.dir}" quiet="true"/>
+ </target>
+
+ <target name="-load.properties">
+ <property file="ant.properties"/>
+ </target>
+
+ <target name="-init" depends="-load.properties">
+ <mkdir dir="${build.dir}"/>
+ </target>
+
+ <target name="build.classes" depends="-init">
+ <mkdir dir="${build.dir}/classes"/>
+ <javac srcdir="${src.dir}"
+ destdir="${build.dir}/classes"
+ includes="**/*.java"
+ deprecation="off"
+ debug="on"
+ source="1.4">
+ <classpath>
+ <pathelement location="${lib.dir}/jargs-1.0.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="build.jar" depends="build.classes">
+ <mkdir dir="${build.dir}/jar"/>
+ <unjar src="${lib.dir}/jargs-1.0.jar" dest="${build.dir}/jar"/>
+ <copy todir="${build.dir}/jar">
+ <fileset dir="${build.dir}/classes" includes="**/*.class"/>
+ </copy>
+ <jar destfile="${build.dir}/${jar.name}" basedir="${build.dir}/jar">
+ <manifest>
+ <attribute name="Main-Class" value="net.nczonline.web.combiner.Combiner"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="build.dist.package" depends="build.jar">
+ <mkdir dir="${build.dir}/${dist.package.name}"/>
+ <mkdir dir="${build.dir}/${dist.package.name}/build"/>
+ <copy file="${build.dir}/${jar.name}" todir="${build.dir}/${dist.package.name}/build"/>
+ <copy todir="${build.dir}/${dist.package.name}">
+ <fileset dir=".">
+ <include name="ant.properties"/>
+ <include name="build.xml"/>
+ <include name="doc/**/*"/>
+ <include name="lib/**/*"/>
+ <include name="src/**/*"/>
+ <exclude name="**/.git"/>
+ </fileset>
+ </copy>
+ <zip destfile="${build.dir}/${dist.package.name}.zip"
+ basedir="${build.dir}"
+ includes="${dist.package.name}/**/*"/>
+ </target>
+
+</project>
BIN  lib/jargs-1.0.jar
Binary file not shown
146 src/net/nczonline/web/combiner/Combiner.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2009 Nicholas C. Zakas. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package net.nczonline.web.combiner;
+
+import jargs.gnu.CmdLineParser;
+import java.io.*;
+import java.nio.charset.Charset;
+
+/*
+ * This file heavily inspired and based on YUI Compressor.
+ * http://github.com/yui/yuicompressor
+ */
+
+public class Combiner {
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) {
+
+ //default settings
+ boolean verbose = false;
+ boolean separator = false;
+ boolean eliminateUnused = false;
+
+ //boolean keepAll = true;
+ String charset = null;
+ String outputFilename = null;
+ Writer out = null;
+
+ //initialize command line parser
+ CmdLineParser parser = new CmdLineParser();
+ CmdLineParser.Option verboseOpt = parser.addBooleanOption('v', "verbose");
+ CmdLineParser.Option helpOpt = parser.addBooleanOption('h', "help");
+ CmdLineParser.Option charsetOpt = parser.addStringOption("charset");
+ CmdLineParser.Option outputFilenameOpt = parser.addStringOption('o', "output");
+ CmdLineParser.Option separatorOpt = parser.addBooleanOption('s', "separator");
+ CmdLineParser.Option eliminateOpt = parser.addBooleanOption('e', "eliminate");
+
+ try {
+
+ //parse the arguments
+ parser.parse(args);
+
+ //figure out if the help option has been executed
+ Boolean help = (Boolean) parser.getOptionValue(helpOpt);
+ if (help != null && help.booleanValue()) {
+ usage();
+ System.exit(0);
+ }
+
+ //determine boolean options
+ verbose = parser.getOptionValue(verboseOpt) != null;
+ separator = parser.getOptionValue(separatorOpt) != null;
+ eliminateUnused = parser.getOptionValue(eliminateOpt) != null;
+
+ //check for charset
+ charset = (String) parser.getOptionValue(charsetOpt);
+ if (charset == null || !Charset.isSupported(charset)) {
+ charset = System.getProperty("file.encoding");
+ if (charset == null) {
+ charset = "UTF-8";
+ }
+ if (verbose) {
+ System.err.println("[INFO] Using charset " + charset);
+ }
+ }
+
+ //get the file arguments
+ String[] fileArgs = parser.getRemainingArgs();
+
+ //need to have at least one file
+ if (fileArgs.length == 0){
+ System.err.println("No files specified.");
+ System.exit(1);
+ }
+
+ //get output filename
+ outputFilename = (String) parser.getOptionValue(outputFilenameOpt);
+
+ if (outputFilename == null) {
+ out = new OutputStreamWriter(System.out, charset);
+ } else {
+ if (verbose){
+ System.err.println("[INFO] Output file is '" + (new File(outputFilename)).getAbsolutePath() + "'");
+ }
+ out = new OutputStreamWriter(new FileOutputStream(outputFilename), charset);
+ }
+
+ FileCombiner combiner = new FileCombiner();
+ combiner.combine(out, fileArgs, charset, verbose, separator, eliminateUnused);
+
+
+ } catch (CmdLineParser.OptionException e) {
+ usage();
+ System.exit(1);
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(1);
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Outputs help information to the console.
+ */
+ private static void usage() {
+ System.out.println(
+ "\nUsage: java -jar combiner-x.y.z.jar [options] [input files]\n\n"
+
+ + "Global Options\n"
+ + " -h, --help Displays this information\n"
+ + " --charset <charset> Read the input file using <charset>\n"
+ + " -v, --verbose Display informational messages and warnings\n"
+ + " -s, --separator Output a separator between combined files\n"
+ + " -e, --eliminate Eliminates any files that aren't explicitly required.\n"
+ + " -o <file> Place the output into <file>. Defaults to stdout.");
+ }
+}
271 src/net/nczonline/web/combiner/FileCombiner.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2009 Nicholas C. Zakas. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package net.nczonline.web.combiner;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class FileCombiner {
+
+ private HashMap sourceFiles = null;
+ private ArrayList todo = null;
+
+ /**
+ * Creates a new FileCombiner object.
+ */
+ public FileCombiner(){
+ this.sourceFiles = new HashMap();
+ this.todo = new ArrayList();
+ }
+
+ /**
+ * Combines a list of files and outputs the result onto the given writer.
+ * @param out Where to place the output.
+ * @param files The files to combine.
+ * @param charset The character set to use.
+ * @param verbose Indicates if warnings and additional information should be output.
+ * @param separator Indicates if a separator should be output between files in the final output.
+ * @param eliminateUnused Indicates if unused files (those with no dependencies and upon which nothing depends) should be eliminated.
+ */
+ public void combine(Writer out, File[] files, String charset, boolean verbose, boolean separator, boolean eliminateUnused){
+ processSourceFiles(files, charset, verbose);
+ SourceFile[] finalFiles = constructFileList(verbose, eliminateUnused);
+ writeToOutput(out, finalFiles, verbose, separator);
+ }
+
+ /**
+ * Combines a list of files and outputs the result onto the given writer.
+ * @param out Where to place the output.
+ * @param files The filenames of the files to combine.
+ * @param charset The character set to use.
+ * @param verbose Indicates if warnings and additional information should be output.
+ * @param separator Indicates if a separator should be output between files in the final output.
+ * @param eliminateUnused Indicates if unused files (those with no dependencies and upon which nothing depends) should be eliminated.
+ */
+ public void combine(Writer out, String[] filenames, String charset, boolean verbose, boolean separator, boolean eliminateUnused){
+ ArrayList files = new ArrayList();
+
+ for (int i=0; i < filenames.length; i++){
+ File file = new File(filenames[i]);
+ if (file.isFile()){
+ files.add(file);
+ if (verbose){
+ System.err.println("[INFO] Adding file '" + file.getAbsolutePath() + "'");
+ }
+ } else {
+ if (verbose){
+ System.err.println("[INFO] Couldn't find file '" + filenames[i] + "'");
+ }
+
+ }
+ }
+
+ File[] finalFiles = new File[files.size()];
+ files.toArray(finalFiles);
+ combine(out, finalFiles, charset, verbose, separator, eliminateUnused);
+ }
+
+ private void processSourceFiles(File[] files, String charset, boolean verbose){
+ //add to ToDo list
+ for (int i=0; i < files.length; i++){
+ todo.add(files[i]);
+ }
+
+ //process files
+ for (int i=0; i < todo.size(); i++){
+ //get a source file object
+ SourceFile depSourceFile = getSourceFile((File) todo.get(i));
+
+ //if there's no contents, then it needs to be processed
+ if (depSourceFile.getContents() == null){
+ processSourceFile((File) todo.get(i), charset, verbose);
+ }
+ }
+ }
+
+ private SourceFile getSourceFile(File file){
+ SourceFile sourceFile = null;
+ if (sourceFiles.containsKey(file.getAbsolutePath())){
+ return (SourceFile) sourceFiles.get(file.getAbsolutePath());
+ } else {
+ sourceFile = new SourceFile(file);
+ sourceFiles.put(file.getAbsolutePath(), sourceFile);
+ return sourceFile;
+ }
+
+ }
+
+ private void processSourceFile(File file, String charset, boolean verbose) {
+ SourceFile sourceFile = getSourceFile(file);
+
+ //if it already has dependencies, then it's already been processed (prevents infinite loop if a circular dependency is detected)
+ if (sourceFile.hasDependencies()){
+ return;
+ }
+
+ try {
+ Reader in = new InputStreamReader(new FileInputStream(file), charset);
+ StringBuffer fileData = new StringBuffer();
+ String filename = null;
+ File depFile = null;
+ int requirements = 0;
+
+ if (verbose){
+ System.err.println("[INFO] Processing file '" + file.getAbsolutePath() + "'");
+ }
+
+ int c = 0, prev=0;
+
+ while((c = in.read()) != -1){
+ if ((char)c == '/' && (char)prev != '*'){
+ char[] buf = new char[9];
+ in.read(buf, 0, 9);
+ if (String.valueOf(buf).equals("*requires")){
+ filename = "";
+ while ((c = in.read()) != 0){
+ if ((char)c == '*'){
+ c = in.read();
+ if ((char)c == '/'){
+ break;
+ } else {
+ System.err.println("[ERROR] Invalid requires comment.");
+ System.exit(1);
+ }
+ } else {
+ filename += String.valueOf((char)c);
+ }
+ }
+
+ filename = filename.trim();
+
+ if (verbose){
+ System.err.println("[INFO] ... has dependency on " + filename);
+ }
+
+ if (!filename.startsWith("/") && !filename.startsWith("\\")){
+ filename = sourceFile.getDirectory() + filename;
+ }
+
+ depFile = new File(filename);
+
+ //verify that the file actually exists
+ if (depFile.isFile()){
+
+ //get a source file object
+ SourceFile depSourceFile = getSourceFile(depFile);
+
+ //if there's no contents, then it needs to be processed
+ if (depSourceFile.getContents() == null){
+ todo.add(depFile);
+ }
+ sourceFile.addDependency(depSourceFile);
+ } else {
+ System.err.println("[ERROR] Dependency file not found: '" + filename + "'");
+ System.exit(1);
+ }
+
+ requirements++;
+ } else {
+ fileData.append((char)c);
+ fileData.append(buf);
+ }
+ } else {
+ fileData.append((char)c);
+ }
+
+ prev = c;
+ }
+
+ sourceFile.setContents(fileData.toString());
+ in.close();
+
+ if (verbose && requirements == 0){
+ System.err.println("[INFO] ... no dependencies found.");
+ }
+
+ } catch (IOException e) {
+ System.err.println(e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ private SourceFile[] constructFileList(boolean verbose, boolean eliminateUnused){
+ ArrayList finalFiles = new ArrayList();
+ SourceFile[] files = new SourceFile[sourceFiles.size()];
+ sourceFiles.values().toArray(files);
+
+ //check for circular references
+ for (int i=0; i < files.length; i++){
+
+ if (verbose){
+ System.err.println("[INFO] Verifying dependencies of '" + files[i].getName() + "'");
+ }
+
+ for (int j=i+1; j < files.length; j++){
+
+ boolean dependsOn = files[i].hasDependency(files[j]);
+ boolean isDependencyOf = files[j].hasDependency(files[i]);
+
+ if (dependsOn && isDependencyOf){
+ System.err.println("[ERROR] Circular dependencies: '" + files[i].getName() + "' and '" + files[j].getName() + "'");
+ System.exit(1);
+ } else if (!eliminateUnused || (dependsOn || isDependencyOf)) {
+ if (!finalFiles.contains(files[i])){
+ finalFiles.add(files[i]);
+ }
+ if (!finalFiles.contains(files[j])){
+ finalFiles.add(files[j]);
+ }
+ }
+ }
+ }
+ SourceFile[] finalSourceFiles = new SourceFile[finalFiles.size()];
+ finalFiles.toArray(finalSourceFiles);
+ java.util.Arrays.sort(finalSourceFiles, new SourceFileComparator());
+ return finalSourceFiles;
+ }
+
+ private void writeToOutput(Writer out, SourceFile[] finalFiles, boolean verbose, boolean separator){
+ try {
+ for (int i=0; i < finalFiles.length; i++){
+ if (verbose){
+ System.err.println("[INFO] Adding '" + finalFiles[i].getName() + "' to output.");
+ }
+ if (separator){
+ out.write("\n/*------" + finalFiles[i].getName() + "------*/\n");
+ }
+ out.write(finalFiles[i].getContents());
+ }
+ } catch (IOException ex) {
+ System.err.println(ex.getMessage());
+ System.exit(1);
+ }
+ }
+
+}
100 src/net/nczonline/web/combiner/SourceFile.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009 Nicholas C. Zakas. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package net.nczonline.web.combiner;
+
+
+import java.io.*;
+import java.util.ArrayList;
+
+public class SourceFile {
+
+ private File file = null;
+ private ArrayList dependencies = null;
+ private String contents = null;
+
+ /**
+ * Creates a new SourceFile based on a file.
+ * @param file
+ */
+ public SourceFile(File file){
+ this.file = file;
+ dependencies = new ArrayList();
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public String getName(){
+ return file.getAbsolutePath();
+ }
+
+ public String getDirectory(){
+ String path = file.getAbsolutePath();
+ return path.substring(0, path.lastIndexOf(File.separator)+1);
+ }
+
+ public String getContents() {
+ return contents;
+ }
+
+ public void setContents(String contents) {
+ this.contents = contents;
+ }
+
+ public void addDependency(SourceFile dependency){
+ dependencies.add(dependency);
+ }
+
+ public SourceFile[] getDependencies() {
+ SourceFile[] deps = new SourceFile[dependencies.size()];
+ dependencies.toArray(deps);
+ return deps;
+ }
+
+ public int getDependencyCount(){
+ return dependencies.size();
+ }
+
+ public boolean hasDependencies(){
+ return !dependencies.isEmpty();
+ }
+
+ public boolean hasDependency(String filename){
+ boolean found = false;
+ for (int i=0; i < dependencies.size() && !found; i++){
+ SourceFile temp = (SourceFile) dependencies.get(i);
+ found = temp.getName().equals(filename);
+ }
+ return found;
+ }
+
+ public boolean hasDependency(File file){
+ return hasDependency(file.getAbsolutePath());
+ }
+
+ public boolean hasDependency(SourceFile file){
+ return hasDependency(file.getName());
+ }
+
+}
43 src/net/nczonline/web/combiner/SourceFileComparator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009 Nicholas C. Zakas. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package net.nczonline.web.combiner;
+
+import java.util.Comparator;
+
+public class SourceFileComparator implements Comparator {
+
+ public int compare(Object o, Object o1) {
+ SourceFile file1 = (SourceFile) o;
+ SourceFile file2 = (SourceFile) o1;
+
+ if (file1.hasDependency(file2.getName())){
+ return 1;
+ } else if (file2.hasDependency(file1.getName())){
+ return -1;
+ } else {
+ SourceFile[] deps1 = file1.getDependencies();
+ SourceFile[] deps2 = file2.getDependencies();
+ return deps1.length - deps2.length;
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.