Skip to content

Commit

Permalink
Continued restruct
Browse files Browse the repository at this point in the history
  • Loading branch information
ffrr committed Dec 13, 2011
1 parent ca81eab commit 1bb4d59
Show file tree
Hide file tree
Showing 186 changed files with 11,879 additions and 0 deletions.
@@ -0,0 +1,41 @@
package com.digmia.maven.plugin.extjsbuilder;

import com.digmia.maven.plugin.extjsbuilder.util.FileHelper;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

/**
*
* @author fk
*/
public class BuildWriter {
private FileHelper fileHelper;
private Global global;

public BuildWriter(Global global) {
fileHelper = new FileHelper(true, false, "UTF-8");
this.global = global;
}

public void buildFromOrderedList(List<JsClass> list) throws IOException {

global.getOutputFile().createNewFile();
FileWriter writer = new FileWriter(global.getOutputFile());

try {
for(JsClass klass: list) {
File f = klass.getFile();
String s = fileHelper.readFileToString(f);
writer.append(s);

//append newline after each file
writer.append(String.format("%n"));
}
} finally {
writer.close();
}
}

}
@@ -0,0 +1,121 @@
package com.digmia.maven.plugin.extjsbuilder;

import com.digmia.maven.plugin.extjsbuilder.extract.DefaultRegexBasedExtractor.ExtractionError;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;

/**
* @author fk
*/
public class DependencyCollector {

private Global global;
private DefaultJsClassParser classParser;

private static class OrderingSession {
private Map<String, JsClass> unorderedMap;
private JsClass root;
private Collection<JsClass> bootstrapClasses;
private Map<String, JsClass> orderedMap = new LinkedHashMap<String, JsClass>();

public OrderingSession(JsClass root, Map<String, JsClass> unorderedMap) {
this.root = root; this.unorderedMap = unorderedMap;
}

public List<JsClass> getOrderedClassList() {
List<JsClass> orderedList = new LinkedList<JsClass>();
if(orderedMap.isEmpty()) {
orderedMap.put(root.getClassName(), root);
traverse(root, new LinkedList<String>());
}
//the root dep should be last, again, remove and add
orderedMap.remove(root.getClassName());

orderedList.addAll(orderedMap.values());
if(bootstrapClasses != null) orderedList.addAll(bootstrapClasses);
Collections.reverse(orderedList);
orderedList.add(root);
return orderedList;
}

private void traverse(JsClass currentClass, List<String> parentVector) {
String currentClassName = currentClass.getClassName();

//if the vector of parent class names already contains this class name
//it effectively means there is a circular dependency somewhere along the chain
//a file cannot depend on itself, throw an assertion error
assert !parentVector.contains(currentClassName): "Circular dependency, exiting.";
parentVector.add(currentClassName);

//if this dependency exists in the map, it means it was already required by a class up in the dependency chain
//we need to push it lower in the chain

//so we remove it if it exists (if it does not, nothing happens on removal
orderedMap.remove(currentClassName);

//and put it back again, which effectively pushed it forward
orderedMap.put(currentClassName, currentClass);

for(String dependencyName: currentClass.getDependencies()) {
JsClass dependency = unorderedMap.get(dependencyName);
assert dependency instanceof JsClass: String.format("Dependency %s required by %s not found!", dependencyName, currentClassName);
traverse(dependency, parentVector);
}
//remove the current class from parent vector after taking care of it's dependency chain
parentVector.remove(currentClassName);
}

public OrderingSession setBootstrapClasses(Collection<JsClass> bootstrapClasses) {
this.bootstrapClasses = bootstrapClasses;
return this;
}
}

public DependencyCollector(Global global) {
this.global = global;
classParser = new DefaultJsClassParser(this.global);
}


public List<JsClass> collectDependencies() {
String appRootClassName = classParser.getClassNameFromFilePath(global.getAppRootFile());
Map<String, JsClass> unorderedDependencyMap = createClassMap(collectFiles());
JsClass rootClass = unorderedDependencyMap.get(appRootClassName);
List<JsClass> orderedDependencyList = new OrderingSession(rootClass, unorderedDependencyMap)
.setBootstrapClasses(
createClassMap(global.getBootstrapFileList(), false).values())
.getOrderedClassList();
return orderedDependencyList;
}


private Collection<File> collectFiles() {
return FileUtils.listFiles(global.getAppDirectory(), new String[] {"js"}, true);
}

private Map<String, JsClass> createClassMap(Collection<File> files) {
return createClassMap(files, true);
}

private Map<String, JsClass> createClassMap(Collection<File> files, boolean parseDependencies) {

Map<String, JsClass> out = new LinkedHashMap<String, JsClass>();

try {
for(File f: files) {
JsClass jsClass = classParser.parse(f, parseDependencies);
out.put(jsClass.getClassName(), jsClass);
}
} catch(ExtractionError ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
return out;
}

}
@@ -0,0 +1,159 @@
package com.digmia.maven.plugin.extjsbuilder.extract;

import com.digmia.maven.plugin.extjsbuilder.Global;
import com.digmia.maven.plugin.extjsbuilder.JsClass;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;

/**
*
* @author fk
*/
public class DefaultRegexBasedExtractor implements Extractor {

private Global global;

private static final Pattern PATTERN_ARRAY = Pattern.compile("((requires|extend|controllers|views|models|stores)\\s*:\\s*\\[([A-Za-z0-9_.',\\s\\/]*?)\\]\\s*)", Pattern.DOTALL);
private static final Pattern PATTERN_STRING = Pattern.compile("((requires|extend|controllers|views|models|stores)\\s*:\\s*([A-Za-z0-9_.']+)\\s*)", Pattern.DOTALL);

private static final Pattern PATTERN_BLOCKCOMMENTS = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
private static final Pattern PATTERN_LINECOMMENTS = Pattern.compile("//.*", Pattern.MULTILINE);

private static final List<TypeExtractionMapping> extractionMappings = new LinkedList<TypeExtractionMapping>() {{
add(new TypeExtractionMapping(JsClass.Type.CONTROLLER, "controllers", "controller"));
add(new TypeExtractionMapping(JsClass.Type.MODEL, "models", "model"));
add(new TypeExtractionMapping(JsClass.Type.STORE, "stores", "store"));
add(new TypeExtractionMapping(JsClass.Type.VIEW, "views", "view"));
}};


private static class TypeExtractionMapping {

public final JsClass.Type type;
public final String dependencyProperty;
public final String folderName;

TypeExtractionMapping(JsClass.Type type, String dependencyProperty, String folderName) {
this.type = type; this.dependencyProperty = dependencyProperty; this.folderName = folderName;
}
}
public static class ExtractionError extends Exception {
public ExtractionError(String msg) { super(msg); }
public ExtractionError(String msg, Throwable ex) { super(msg, ex); }
}

public DefaultRegexBasedExtractor(Global global) {
this.global = global;
}


@Override
public List<String> extractDependencies(JsClass klass) throws ExtractionError {
try {
String contents = FileUtils.readFileToString(klass.getFile());
contents = clean(contents);
return runMatchers(contents);
} catch (IOException ex) {
throw new ExtractionError(ex.getMessage(), ex);
}
}

private String clean(String contents) {
return PATTERN_LINECOMMENTS.matcher(
PATTERN_BLOCKCOMMENTS.matcher(contents).replaceAll("")
).replaceAll("");
}

private List<String> runMatchers(String contents) {

Map<JsClass.Type, List<String>> acc = createAcc();
List<String> out = new LinkedList<String>();

Matcher arrayMatcher = PATTERN_ARRAY.matcher(contents);
collectDependenciesFromArrayMatcher(arrayMatcher, acc);

Matcher stringMatcher = PATTERN_STRING.matcher(contents);
collectDependenciesFromStringMatcher(stringMatcher, acc);

for(List<String>list: acc.values()) {
Collections.reverse(list);
out.addAll(list);
}

return out;
}


private Map<JsClass.Type, List<String>> createAcc() {

Map<JsClass.Type, List<String>> acc = new LinkedHashMap<JsClass.Type, List<String>>();


//in reversed order - first load required libs, the controllers, then etc. etc.
acc.put(JsClass.Type.VIEW, new LinkedList<String>());
acc.put(JsClass.Type.STORE, new LinkedList<String>());
acc.put(JsClass.Type.MODEL, new LinkedList<String>());
acc.put(JsClass.Type.CONTROLLER, new LinkedList<String>());
acc.put(JsClass.Type.LIB, new LinkedList<String>());

return acc;
}

private void collectDependenciesFromStringMatcher(Matcher m, Map<JsClass.Type, List<String>> acc) {
while(m.find()) {
String key = m.group(2);
String rawValue = m.group(3);
TypeExtractionMapping tem = findTypeExtractionMapping(key);
String path = processClassPath(rawValue, tem);
if(!isExcluded(path) && !path.isEmpty()) acc.get(tem.type).add(path);
}
}

private void collectDependenciesFromArrayMatcher(Matcher m, Map<JsClass.Type, List<String>> acc) {
while(m.find()) {
String key = m.group(2);
String values = m.group(3);
for(String rawValue: values.split(",")) {
TypeExtractionMapping tem = findTypeExtractionMapping(key);
String path = processClassPath(rawValue, tem);
if(!isExcluded(path) && !path.isEmpty()) acc.get(tem.type).add(path);
}
}
}

private TypeExtractionMapping findTypeExtractionMapping(String key) {
for(TypeExtractionMapping tem: extractionMappings) {
if(tem.dependencyProperty.equals(key)) return tem;
}

return new TypeExtractionMapping(JsClass.Type.LIB, "", "lib");
}


private String processClassPath(String rawPath, TypeExtractionMapping tem) {
String path = rawPath.replace("'", "").replace("\"", "").trim();
if (tem.type != JsClass.Type.LIB) {
// if this has a mapping, add the mapping prefix
return tem.folderName + "." + path;
} else {
// if not, just delete the global app prefix
return path.replace(global.getAppPrefix() + ".", "");
}

}

private Boolean isExcluded(String path) {
for(String prefix: global.getExternalPackagePrefixes()) {
if(path.startsWith(prefix)) return true;
}
return false;
}

}
@@ -0,0 +1,13 @@
package com.digmia.maven.plugin.extjsbuilder.extract;

import com.digmia.maven.plugin.extjsbuilder.JsClass;
import com.digmia.maven.plugin.extjsbuilder.extract.DefaultRegexBasedExtractor.ExtractionError;
import java.util.List;

/**
*
* @author fk
*/
public interface Extractor {
public List<String> extractDependencies(JsClass klass) throws ExtractionError;
}
@@ -0,0 +1,24 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.digmia.maven.plugin.extjsbuilder.future;

import com.digmia.maven.plugin.extjsbuilder.extract.Extractor;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

/**
* @author fk
*/
public interface ContextWrapper {

void initialize(Extractor civ);
void initialize();

void destroy();
Scriptable getScope();
Context getContext();

Boolean isInitialized();
}

0 comments on commit 1bb4d59

Please sign in to comment.