Merge branch 'master' of git@github.com:280north/cappuccino

This commit is contained in:
Ross Boucher
2008-09-30 15:22:30 -07:00
5 changed files with 1372 additions and 1 deletions
+1 -1
View File
@@ -861,7 +861,7 @@ var CTRL_KEY_CODE = 17;
@end
var CLICK_SPACE_DELTA = 5.0,
CLICK_TIME_DELTA = document.addEventListener ? 350.0 : 1000.0;
CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0;
var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
{
Binary file not shown.
+767
View File
@@ -0,0 +1,767 @@
/*
* Pure JavaScript Browser Environment
* By John Resig <http://ejohn.org/>
* Copyright 2008 John Resig, under the MIT License
*/
// The window Object
var window = this;
(function(){
// Browser Navigator
window.navigator = {
get userAgent(){
return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3";
}
};
var curLocation = (new java.io.File("./")).toURL();
window.__defineSetter__("location", function(url){
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = function(){
curLocation = new java.net.URL( curLocation, url );
window.document = xhr.responseXML;
var event = document.createEvent();
event.initEvent("load");
window.dispatchEvent( event );
};
xhr.send();
});
window.__defineGetter__("location", function(url){
return {
get protocol(){
return curLocation.getProtocol() + ":";
},
get href(){
return curLocation.toString();
},
toString: function(){
return this.href;
}
};
});
// Timers
var timers = [];
window.setTimeout = function(fn, time){
var num;
return num = setInterval(function(){
fn();
clearInterval(num);
}, time);
};
window.setInterval = function(fn, time){
var num = timers.length;
timers[num] = new java.lang.Thread(new java.lang.Runnable({
run: function(){
while (true){
java.lang.Thread.currentThread().sleep(time);
fn();
}
}
}));
timers[num].start();
return num;
};
window.clearInterval = function(num){
if ( timers[num] ) {
timers[num].stop();
delete timers[num];
}
};
// Window Events
var events = [{}];
window.addEventListener = function(type, fn){
if ( !this.uuid || this == window ) {
this.uuid = events.length;
events[this.uuid] = {};
}
if ( !events[this.uuid][type] )
events[this.uuid][type] = [];
if ( events[this.uuid][type].indexOf( fn ) < 0 )
events[this.uuid][type].push( fn );
};
window.removeEventListener = function(type, fn){
if ( !this.uuid || this == window ) {
this.uuid = events.length;
events[this.uuid] = {};
}
if ( !events[this.uuid][type] )
events[this.uuid][type] = [];
events[this.uuid][type] =
events[this.uuid][type].filter(function(f){
return f != fn;
});
};
window.dispatchEvent = function(event){
if ( event.type ) {
if ( this.uuid && events[this.uuid][event.type] ) {
var self = this;
events[this.uuid][event.type].forEach(function(fn){
fn.call( self, event );
});
}
if ( this["on" + event.type] )
this["on" + event.type].call( self, event );
}
};
// DOM Document
window.DOMDocument = function(file){
this._file = file;
this._dom = Packages.javax.xml.parsers.
DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(file);
if ( !obj_nodes.containsKey( this._dom ) )
obj_nodes.put( this._dom, this );
};
DOMDocument.prototype = {
get nodeType(){
return 9;
},
createTextNode: function(text){
return makeNode( this._dom.createTextNode(
text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")) );
},
createElement: function(name){
return makeNode( this._dom.createElement(name.toLowerCase()) );
},
getElementsByTagName: function(name){
return new DOMNodeList( this._dom.getElementsByTagName(
name.toLowerCase()) );
},
getElementsByName: function(name){
var elems = this._dom.getElementsByTagName("*"), ret = [];
ret.item = function(i){ return this[i]; };
ret.getLength = function(){ return this.length; };
for ( var i = 0; i < elems.length; i++ ) {
var elem = elems.item(i);
if ( elem.getAttribute("name") == name )
ret.push( elem );
}
return new DOMNodeList( ret );
},
getElementById: function(id){
var elems = this._dom.getElementsByTagName("*");
for ( var i = 0; i < elems.length; i++ ) {
var elem = elems.item(i);
if ( elem.getAttribute("id") == id )
return makeNode(elem);
}
return null;
},
get body(){
return this.getElementsByTagName("body")[0];
},
get documentElement(){
return makeNode( this._dom.getDocumentElement() );
},
get ownerDocument(){
return null;
},
addEventListener: window.addEventListener,
removeEventListener: window.removeEventListener,
dispatchEvent: window.dispatchEvent,
get nodeName() {
return "#document";
},
importNode: function(node, deep){
return makeNode( this._dom.importNode(node._dom, deep) );
},
toString: function(){
return "Document" + (typeof this._file == "string" ?
": " + this._file : "");
},
get innerHTML(){
return this.documentElement.outerHTML;
},
get defaultView(){
return {
getComputedStyle: function(elem){
return {
getPropertyValue: function(prop){
prop = prop.replace(/\-(\w)/g,function(m,c){
return c.toUpperCase();
});
var val = elem.style[prop];
if ( prop == "opacity" && val == "" )
val = "1";
return val;
}
};
}
};
},
createEvent: function(){
return {
type: "",
initEvent: function(type){
this.type = type;
}
};
}
};
function getDocument(node){
return obj_nodes.get(node);
}
// DOM NodeList
window.DOMNodeList = function(list){
this._dom = list;
this.length = list.getLength();
for ( var i = 0; i < this.length; i++ ) {
var node = list.item(i);
this[i] = makeNode( node );
}
};
DOMNodeList.prototype = {
toString: function(){
return "[ " +
Array.prototype.join.call( this, ", " ) + " ]";
},
get outerHTML(){
return Array.prototype.map.call(
this, function(node){return node.outerHTML;}).join('');
}
};
// DOM Node
window.DOMNode = function(node){
this._dom = node;
};
DOMNode.prototype = {
get nodeType(){
return this._dom.getNodeType();
},
get nodeValue(){
return this._dom.getNodeValue();
},
get nodeName() {
return this._dom.getNodeName();
},
get childNodes(){
return new DOMNodeList( this._dom.getChildNodes() );
},
cloneNode: function(deep){
return makeNode( this._dom.cloneNode(deep) );
},
get ownerDocument(){
return getDocument( this._dom.ownerDocument );
},
get documentElement(){
return makeNode( this._dom.documentElement );
},
get parentNode() {
return makeNode( this._dom.getParentNode() );
},
get nextSibling() {
return makeNode( this._dom.getNextSibling() );
},
get previousSibling() {
return makeNode( this._dom.getPreviousSibling() );
},
toString: function(){
return '"' + this.nodeValue + '"';
},
get outerHTML(){
return this.nodeValue;
}
};
window.DOMComment = function(node){
this._dom = node;
};
DOMComment.prototype = extend(new DOMNode(), {
get nodeType(){
return 8;
},
get outerHTML(){
return "<!--" + this.nodeValue + "-->";
}
});
// DOM Element
window.DOMElement = function(elem){
this._dom = elem;
this.style = {
get opacity(){ return this._opacity; },
set opacity(val){ this._opacity = val + ""; }
};
// Load CSS info
var styles = (this.getAttribute("style") || "").split(/\s*;\s*/);
for ( var i = 0; i < styles.length; i++ ) {
var style = styles[i].split(/\s*:\s*/);
if ( style.length == 2 )
this.style[ style[0] ] = style[1];
}
if ( this.nodeName == "FORM" ) {
this.__defineGetter__("elements", function(){
return this.getElementsByTagName("*");
});
this.__defineGetter__("length", function(){
var elems = this.elements;
for ( var i = 0; i < elems.length; i++ ) {
this[i] = elems[i];
}
return elems.length;
});
}
if ( this.nodeName == "SELECT" ) {
this.__defineGetter__("options", function(){
return this.getElementsByTagName("option");
});
}
this.defaultValue = this.value;
};
DOMElement.prototype = extend( new DOMNode(), {
get nodeName(){
return this.tagName;
},
get tagName(){
return this._dom.getTagName().toUpperCase();
},
toString: function(){
return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">";
},
get outerHTML(){
var ret = "<" + this.tagName, attr = this.attributes;
for ( var i in attr )
ret += " " + i + "='" + attr[i] + "'";
if ( this.childNodes.length || this.nodeName == "SCRIPT" )
ret += ">" + this.childNodes.outerHTML +
"</" + this.tagName + ">";
else
ret += "/>";
return ret;
},
get attributes(){
var attr = {}, attrs = this._dom.getAttributes();
for ( var i = 0; i < attrs.getLength(); i++ )
attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue;
return attr;
},
get innerHTML(){
return this.childNodes.outerHTML;
},
set innerHTML(html){
html = html.replace(/<\/?([A-Z]+)/g, function(m){
return m.toLowerCase();
}).replace(/&nbsp;/g, " ");
var nodes = this.ownerDocument.importNode(
new DOMDocument( new java.io.ByteArrayInputStream(
(new java.lang.String("<wrap>" + html + "</wrap>"))
.getBytes("UTF8"))).documentElement, true).childNodes;
while (this.firstChild)
this.removeChild( this.firstChild );
for ( var i = 0; i < nodes.length; i++ )
this.appendChild( nodes[i] );
},
get textContent(){
return nav(this.childNodes);
function nav(nodes){
var str = "";
for ( var i = 0; i < nodes.length; i++ )
if ( nodes[i].nodeType == 3 )
str += nodes[i].nodeValue;
else if ( nodes[i].nodeType == 1 )
str += nav(nodes[i].childNodes);
return str;
}
},
set textContent(text){
while (this.firstChild)
this.removeChild( this.firstChild );
this.appendChild( this.ownerDocument.createTextNode(text));
},
style: {},
clientHeight: 0,
clientWidth: 0,
offsetHeight: 0,
offsetWidth: 0,
get disabled() {
var val = this.getAttribute("disabled");
return val != "false" && !!val;
},
set disabled(val) { return this.setAttribute("disabled",val); },
get checked() {
var val = this.getAttribute("checked");
return val != "false" && !!val;
},
set checked(val) { return this.setAttribute("checked",val); },
get selected() {
if ( !this._selectDone ) {
this._selectDone = true;
if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) {
var opt = this.parentNode.getElementsByTagName("option");
if ( this == opt[0] ) {
var select = true;
for ( var i = 1; i < opt.length; i++ )
if ( opt[i].selected ) {
select = false;
break;
}
if ( select )
this.selected = true;
}
}
}
var val = this.getAttribute("selected");
return val != "false" && !!val;
},
set selected(val) { return this.setAttribute("selected",val); },
get className() { return this.getAttribute("class") || ""; },
set className(val) {
return this.setAttribute("class",
val.replace(/(^\s*|\s*$)/g,""));
},
get type() { return this.getAttribute("type") || ""; },
set type(val) { return this.setAttribute("type",val); },
get defaultValue() { return this.getAttribute("defaultValue") || ""; },
set defaultValue(val) { return this.setAttribute("defaultValue",val); },
get value() { return this.getAttribute("value") || ""; },
set value(val) { return this.setAttribute("value",val); },
get src() { return this.getAttribute("src") || ""; },
set src(val) { return this.setAttribute("src",val); },
get id() { return this.getAttribute("id") || ""; },
set id(val) { return this.setAttribute("id",val); },
getAttribute: function(name){
return this._dom.hasAttribute(name) ?
new String( this._dom.getAttribute(name) ) :
null;
},
setAttribute: function(name,value){
this._dom.setAttribute(name,value);
},
removeAttribute: function(name){
this._dom.removeAttribute(name);
},
get childNodes(){
return new DOMNodeList( this._dom.getChildNodes() );
},
get firstChild(){
return makeNode( this._dom.getFirstChild() );
},
get lastChild(){
return makeNode( this._dom.getLastChild() );
},
appendChild: function(node){
this._dom.appendChild( node._dom );
},
insertBefore: function(node,before){
this._dom.insertBefore( node._dom, before ? before._dom : before );
execScripts( node );
function execScripts( node ) {
if ( node.nodeName == "SCRIPT" ) {
if ( !node.getAttribute("src") ) {
eval.call( window, node.textContent );
}
} else {
var scripts = node.getElementsByTagName("script");
for ( var i = 0; i < scripts.length; i++ ) {
execScripts( node );
}
}
}
},
removeChild: function(node){
this._dom.removeChild( node._dom );
},
getElementsByTagName: DOMDocument.prototype.getElementsByTagName,
addEventListener: window.addEventListener,
removeEventListener: window.removeEventListener,
dispatchEvent: window.dispatchEvent,
click: function(){
var event = document.createEvent();
event.initEvent("click");
this.dispatchEvent(event);
},
submit: function(){
var event = document.createEvent();
event.initEvent("submit");
this.dispatchEvent(event);
},
focus: function(){
var event = document.createEvent();
event.initEvent("focus");
this.dispatchEvent(event);
},
blur: function(){
var event = document.createEvent();
event.initEvent("blur");
this.dispatchEvent(event);
},
get contentWindow(){
return this.nodeName == "IFRAME" ? {
document: this.contentDocument
} : null;
},
get contentDocument(){
if ( this.nodeName == "IFRAME" ) {
if ( !this._doc )
this._doc = new DOMDocument(
new java.io.ByteArrayInputStream((new java.lang.String(
"<html><head><title></title></head><body></body></html>"))
.getBytes("UTF8")));
return this._doc;
} else
return null;
}
});
// Helper method for extending one object with another
function extend(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g )
a.__defineGetter__(i, g);
if ( s )
a.__defineSetter__(i, s);
} else
a[i] = b[i];
}
return a;
}
// Helper method for generating the right
// DOM objects based upon the type
var obj_nodes = new java.util.HashMap();
function makeNode(node){
if ( node ) {
if ( !obj_nodes.containsKey( node ) )
obj_nodes.put( node, node.getNodeType() == 1?
new DOMElement( node ) :
node.getNodeType() == 8 ?
new DOMComment( node ) :
new DOMNode( node ) );
return obj_nodes.get(node);
} else
return null;
}
// XMLHttpRequest
// Originally implemented by Yehuda Katz
window.XMLHttpRequest = function(){
this.headers = {};
this.responseHeaders = {};
};
XMLHttpRequest.prototype = {
open: function(method, url, async, user, password){
this.readyState = 1;
if (async)
this.async = true;
this.method = method || "GET";
this.url = url;
this.onreadystatechange();
},
setRequestHeader: function(header, value){
this.headers[header] = value;
},
getResponseHeader: function(header){ },
send: function(data){
var self = this;
function makeRequest(){
var url = new java.net.URL(curLocation, self.url);
if ( url.getProtocol() == "file" ) {
if ( self.method == "PUT" ) {
var out = new java.io.FileWriter(
new java.io.File( new java.net.URI( url.toString() ) ) ),
text = new java.lang.String( data || "" );
out.write( text, 0, text.length() );
out.flush();
out.close();
} else if ( self.method == "DELETE" ) {
var file = new java.io.File( new java.net.URI( url.toString() ) );
file["delete"]();
} else {
var connection = url.openConnection();
connection.connect();
handleResponse();
}
} else {
var connection = url.openConnection();
connection.setRequestMethod( self.method );
// Add headers to Java connection
for (var header in self.headers)
connection.addRequestProperty(header, self.headers[header]);
connection.connect();
// Stick the response headers into responseHeaders
for (var i = 0; ; i++) {
var headerName = connection.getHeaderFieldKey(i);
var headerValue = connection.getHeaderField(i);
if (!headerName && !headerValue) break;
if (headerName)
self.responseHeaders[headerName] = headerValue;
}
handleResponse();
}
function handleResponse(){
self.readyState = 4;
self.status = parseInt(connection.responseCode) || undefined;
self.statusText = connection.responseMessage || "";
var stream = new java.io.InputStreamReader(connection.getInputStream()),
buffer = new java.io.BufferedReader(stream), line;
while ((line = buffer.readLine()) != null)
self.responseText += line;
self.responseXML = null;
if ( self.responseText.match(/^\s*</) ) {
try {
self.responseXML = new DOMDocument(
new java.io.ByteArrayInputStream(
(new java.lang.String(
self.responseText)).getBytes("UTF8")));
} catch(e) {}
}
}
self.onreadystatechange();
}
if (this.async)
(new java.lang.Thread(new java.lang.Runnable({
run: makeRequest
}))).start();
else
makeRequest();
},
abort: function(){},
onreadystatechange: function(){},
getResponseHeader: function(header){
if (this.readyState < 3)
throw new Error("INVALID_STATE_ERR");
else {
var returnedHeaders = [];
for (var rHeader in this.responseHeaders) {
if (rHeader.match(new Regexp(header, "i")))
returnedHeaders.push(this.responseHeaders[rHeader]);
}
if (returnedHeaders.length)
return returnedHeaders.join(", ");
}
return null;
},
getAllResponseHeaders: function(header){
if (this.readyState < 3)
throw new Error("INVALID_STATE_ERR");
else {
var returnedHeaders = [];
for (var header in this.responseHeaders)
returnedHeaders.push( header + ": " + this.responseHeaders[header] );
return returnedHeaders.join("\r\n");
}
},
async: true,
readyState: 0,
responseText: "",
status: 0
};
})();
+340
View File
@@ -0,0 +1,340 @@
var objjPath = OBJJ_LIB+'/Frameworks/Objective-J/Objective-J.js',
bridgePath = OBJJ_LIB+'/bridge.js',
envPath = "/Users/tlrobinson/280North/git/cappuccino/Tools/press/env.js";
/*
param context includes
scope: a global variable containing objj_files hash
processedFiles: hash containing file paths which have already been analyzed
dependencies: hash mapping from paths to an array of global variables defined by that file
[importCallback]: callback function that is called for each imported file (takes importing file path, and imported file path parameters)
[referencedCallback]: callback function that is called for each referenced file (takes referencing file path, referenced file path parameters, and list of tokens)
[importedFiles]: hash that will contain a mapping of file names to a hash of imported files
[referencedFiles]: hash that will contain a mapping of file names to a hash of referenced files (which contains a hash of tokens referenced)
param file is an objj_file object containing path, fragments, content, bundle, etc
*/
function traverseDependencies(context, file)
{
if (context.processedFiles[file.path])
return;
context.processedFiles[file.path] = true;
var ignoreImports = false;
if (context.ignoreAllImports)
{
CPLog.warn("Ignoring all import fragments. ("+file.path+")");
ignoreImports = true;
}
else if (context.ignoreFrameworkImports)
{
var matches = file.path.match(/([^\/]+)\/([^\/]+)\.j$/); // Matches "ZZZ/ZZZ.j" (e.x. AppKit/AppKit.j and Foundation/Foundation.j)
if (matches && matches[1] === matches[2])
{
CPLog.warn("Framework import file! Ignoring all import fragments. ("+file.path+")");
ignoreImports = true;
}
}
if (!file.fragments)
{
if (file.included)
CPLog.warn(file.path + " is included but missing fragments");
else
CPLog.info("Preprocessing " + file.path);
file.fragments = objj_preprocess(file.contents, file.bundle, file);
}
var referencedFiles = {},
importedFiles = {};
CPLog.trace("Processing " + file.path + " fragments ("+file.fragments.length+")");
for (var i = 0; i < file.fragments.length; i++)
{
var fragment = file.fragments[i];
if (fragment.type & FRAGMENT_CODE)
{
var lexer = new objj_lexer(fragment.info, NULL);
var token;
while (token = lexer.skip_whitespace())
{
if (context.dependencies[token])
{
var files = context.dependencies[token]
for (var j = 0; j < files.length; j++)
{
// don't record references to self
if (files[j] != file.path)
{
if (!referencedFiles[files[j]])
referencedFiles[files[j]] = {};
referencedFiles[files[j]][token] = true;
}
}
}
}
}
else if (fragment.type & FRAGMENT_IMPORT)
{
if (ignoreImports)
{
fragment.conditionallyIgnore = true;
}
else
{
var importedFile = findImportInObjjFiles(context.scope, fragment);
if (importedFile)
{
// should never import self, but just in case?
if (importedFile != file.path)
importedFiles[importedFile] = true;
else
CPLog.error("Ignoring self import (why are you importing yourself!?): " + file.path);
}
else
CPLog.error("Couldn't find file for import " + fragment.info + "("+fragment.type+")");
}
}
}
// check each imported file
for (var importedFile in importedFiles)
{
if (importedFile != file.path)
{
if (context.importCallback)
context.importCallback(file.path, importedFile);
if (context.scope.objj_files[importedFile])
traverseDependencies(context, context.scope.objj_files[importedFile]);
else
CPLog.error("Missing imported file: " + importedFile);
}
}
if (context.importedFiles)
context.importedFiles[file.path] = importedFiles;
// check each referenced file
for (var referencedFile in referencedFiles)
{
if (referencedFile != file.path)
{
if (context.referenceCallback)
context.referenceCallback(file.path, referencedFile, referencedFiles[referencedFile]);
if (context.scope.objj_files[referencedFile])
traverseDependencies(context, context.scope.objj_files[referencedFile]);
else
CPLog.error("Missing referenced file: " + referencedFile);
}
}
if (context.referencedFiles)
context.referencedFiles[file.path] = referencedFiles;
}
function findImportInObjjFiles(scope, fragment)
{
var importPath = null;
if (fragment.type & FRAGMENT_LOCAL)
{
//CPLog.debug("Importing local file: " + fragment.info);
var searchPath = fragment.info;
if (scope.objj_files[searchPath])
{
importPath = searchPath;
}
}
else if (fragment.type & FRAGMENT_FILE)
{
//CPLog.debug("Importing search-path file: " + fragment.info);
var count = scope.OBJJ_INCLUDE_PATHS.length;
while (count--)
{
var searchPath = scope.OBJJ_INCLUDE_PATHS[count] + fragment.info;
if (scope.objj_files[searchPath])
{
importPath = searchPath;
break;
}
}
}
else
CPLog.warn("Import fragment not local or file");
return importPath;
}
// given a fresh scope and the path to a root source file, determine which files define each global variable
function findGlobalDefines(context, scope, rootPath)
{
addMockBrowserEnvironment(scope);
var ignore = cloneProperties(scope, true);
ignore['bundle'] = true;
var dependencies = {};
//scope.fragment_evaluate_file_original = scope.fragment_evaluate_file;
//scope.fragment_evaluate_file = function(aFragment)
//{
// //CPLog.trace("Loading "+aFragment.info);
//
// var result = scope.fragment_evaluate_file_original(aFragment);
//
// return result;
//}
scope.fragment_evaluate_code_original = scope.fragment_evaluate_code;
scope.fragment_evaluate_code = function(aFragment)
{
CPLog.debug("Evaling "+aFragment.file.path + " / " + aFragment.bundle.path);
var before = cloneProperties(scope);
var result = scope.fragment_evaluate_code_original(aFragment);
var definedGlobals = {};
diff(before, scope, ignore, definedGlobals, definedGlobals, null);
dependencies[aFragment.file.path] = definedGlobals;
return result;
}
runWithScope(context, scope, function(importName) {
print('Loading from '+OBJJ_INCLUDE_PATHS);
objj_import(importName, true, function() {
print('Callback complete');
});
print('Done');
}, [rootPath]);
//for (var i in scope.objj_included_files)
// CPLog.debug(i + " ==> " + scope.objj_included_files[i]);
return dependencies;
}
function coalesceGlobalDefines(globals)
{
var dependencies = {};
for (var fileName in globals)
{
var fileGlobals = globals[fileName];
for (var globalName in fileGlobals)
{
if (!dependencies[globalName])
dependencies[globalName] = [];
dependencies[globalName].push(fileName);
}
}
return dependencies;
}
// create a new scope loaded with Objective-J
function makeObjjScope(context, debug)
{
// init standard js scope objects
var scope = context.initStandardObjects();
if (debug)
{
scope.objj_alert = print;
scope.debug = true;
}
// give the scope "print"
scope.print = function(value) { Packages.java.lang.System.out.println(value); };
// load and eval fake browser environment
var envSource = readFile(envPath);
if (envSource)
context.evaluateString(scope, envSource, "env.js", 1, null);
else
CPLog.warn("Missing env.js");
// load and eval the bridge
var bridgeSource = readFile(bridgePath);
if (bridgeSource)
context.evaluateString(scope, bridgeSource, "bridge.js", 1, null);
else
CPLog.warn("Missing bridge.js");
// load and eval obj-j
var objjSource = readFile(objjPath);
if (objjSource)
context.evaluateString(scope, objjSource, "Objective-J.js", 1, null);
else
CPLog.warn("Missing Objective-J.js");
return scope;
}
// run a function within the given scope (func can be a function object if the source of the function is returned by toString() as it is by default)
function runWithScope(context, scope, func, arguments)
{
scope.__runWithScopeArgs = arguments || [];
var code = "("+func+").apply(this, this.__runWithScopeArgs); serviceTimeouts();";
return context.evaluateString(scope, code, "<cmd>", 1, null);
}
// add a mock browser environment to the provided scope
function addMockBrowserEnvironment(scope)
{
// TODO: complete this. or use env.js?
scope.Element = function() {
this.style = {}
}
scope.document = {
createElement : function() {
return new scope.Element();
}
}
}
// does a shallow copy of an object. if onlyList is true, it sets each property to "true" instead of the actual value
function cloneProperties(object, onlyList)
{
var results = {}
for (var memeber in object)
results[memeber] = onlyList ? true : object[memeber];
return results;
}
function diff(objectA, objectB, ignore, added, changed, deleted)
{
for (var i in objectB)
if (added && !ignore[i] && typeof objectA[i] == "undefined")
added[i] = true;
for (var i in objectB)
if (changed && !ignore[i] && typeof objectA[i] != "undefined" && typeof objectB[i] != "undefined" && objectA[i] !== objectB[i])
changed[i] = true;
for (var i in objectA)
if (deleted && !ignore[i] && typeof objectB[i] == "undefined")
deleted[i] = true;
}
function allKeys(object)
{
var result = [];
for (var i in object)
result.push(i)
return result.sort();
}
+264
View File
@@ -0,0 +1,264 @@
import <Foundation/CPLog.j>
import "objj-analysis-tools.j"
CPLogRegister(CPLogPrint);
function main()
{
if (args.length < 2)
{
print("Usage: press input_base_file.j output_directory");
return;
}
var rootPath = args[0],
sourceDirectory = dirname(rootPath) || ".",
outputDirectory = args[1];
var cx = Packages.org.mozilla.javascript.Context.enter(),
scope = makeObjjScope(cx);
var frameworks = rootPath.substring(0, rootPath.lastIndexOf("/")+1) + "Frameworks/";
scope.OBJJ_INCLUDE_PATHS = [frameworks];
CPLog.info("OBJJ_INCLUDE_PATHS="+scope.OBJJ_INCLUDE_PATHS);
// phase 1: get global defines
var globals = findGlobalDefines(cx, scope, rootPath);
// coalesce the results
var dependencies = coalesceGlobalDefines(globals);
// phase 2: walk the import tree to determine exactly which files need to be included
var requiredFiles = {};
if (scope.objj_files[rootPath])
{
var context = {
scope : scope,
dependencies : dependencies,
processedFiles : {},
ignoreFrameworkImports : true,
importCallback : function(importing, imported) {
requiredFiles[imported] = true;
},
referenceCallback : function(referencing, referenced) {
requiredFiles[referenced] = true;
}
}
traverseDependencies(context, scope.objj_files[rootPath]);
var count = 0,
total = 0;
for (var path in scope.objj_files)
{
if (requiredFiles[path])
{
CPLog.info("Included: " + path);
count++;
}
else
{
CPLog.warn("Excluded: " + path);
}
total++;
}
CPLog.error("Total required files: " + count + " out of " + total);
}
else
{
CPLog.error("Root file not loaded!");
return;
}
// phase 3: rebuild .sj files with correct imports, copy .j files
var outputFiles = {};
for (var path in requiredFiles)
{
var file = scope.objj_files[path],
filename = basename(path),
directory = dirname(path);
if (file.path != path)
CPLog.warn("Sanity check (file path): " + file.path + " vs. " + path);
if (file.bundle)
{
var bundleDirectory = dirname(file.bundle.path);
if (bundleDirectory != directory)
CPLog.warn("Sanity check (directory path): " + directory + " vs. " + bundleDirectory);
// if it's in a .sj
var dict = file.bundle.info,
replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"];
if (replacedFiles && [replacedFiles containsObject:filename])
{
var staticPath = bundleDirectory + "/" + [dict objectForKey:"CPBundleExecutable"];
if (!outputFiles[staticPath])
{
outputFiles[staticPath] = [];
outputFiles[staticPath].push("@STATIC;1.0;");
}
outputFiles[staticPath].push("p;");
outputFiles[staticPath].push(filename.length+";");
outputFiles[staticPath].push(filename);
for (var i = 0; i < file.fragments.length; i++)
{
if (file.fragments[i].type & FRAGMENT_CODE)
{
outputFiles[staticPath].push("c;");
outputFiles[staticPath].push(file.fragments[i].info.length+";");
outputFiles[staticPath].push(file.fragments[i].info);
}
else if (file.fragments[i].type & FRAGMENT_IMPORT)
{
var ignoreFragment = false;
if (file.fragments[i].conditionallyIgnore)
{
var importPath = findImportInObjjFiles(scope, file.fragments[i]);
if (!importPath || !requiredFiles[importPath])
{
ignoreFragment = true;
}
}
if (!ignoreFragment)
{
if (file.fragments[i].type & FRAGMENT_LOCAL)
{
var relativePath = pathRelativeTo(file.fragments[i].info, directory)
outputFiles[staticPath].push("i;");
outputFiles[staticPath].push(relativePath.length+";");
outputFiles[staticPath].push(relativePath);
}
else if (file.fragments[i].type & FRAGMENT_FILE)
{
outputFiles[staticPath].push("I;");
outputFiles[staticPath].push(file.fragments[i].info.length+";");
outputFiles[staticPath].push(file.fragments[i].info);
}
}
else
CPLog.warn("Ignoring import fragment " + file.fragments[i].info + " in " + path);
}
else
CPLog.error("Unknown fragment type");
}
}
// always output individual .j files
else
{
outputFiles[path] = file.contents;
}
}
else
CPLog.warn("No bundle for " + path)
}
// phase 4: copy everything and write out the new files
var sourceDirectoryFile = new Packages.java.io.File(sourceDirectory),
outputDirectoryFile = new Packages.java.io.File(outputDirectory);
copyDirectory(sourceDirectoryFile, outputDirectoryFile);
for (var path in outputFiles)
{
var file = new java.io.File(outputDirectoryFile, path);
var parent = file.getParentFile();
if (!parent.exists())
{
CPLog.warn(parent + " doesn't exist, creating directories.");
parent.mkdirs();
}
CPLog.info("Writing out " + file);
var writer = new java.io.BufferedWriter(new java.io.FileWriter(file));
if (typeof outputFiles[path] == "string")
writer.write(outputFiles[path]);
else
writer.write(outputFiles[path].join(""));
writer.close();
}
}
// Helper Utilities
// TODO: moved elsewhere?
function copyDirectory(src, dst)
{
CPLog.trace("Copying directory " + src);
dst.mkdirs();
var files = src.listFiles();
for (var i = 0; i < files.length; i++)
{
if (files[i].isFile())
copyFile(files[i], new Packages.java.io.File(dst, files[i].getName()));
else if (files[i].isDirectory())
copyDirectory(files[i], new Packages.java.io.File(dst, files[i].getName()));
}
}
function copyFile(src, dst)
{
CPLog.trace("Copying file " + src);
var input = (new Packages.java.io.FileInputStream(src)).getChannel(),
output = (new Packages.java.io.FileOutputStream(dst)).getChannel();
input.transferTo(0, input.size(), output);
input.close();
output.close();
}
function dirname(path)
{
return path.substring(0, path.lastIndexOf("/"));
}
function basename(path)
{
return path.substring(path.lastIndexOf("/") + 1);
}
function pathRelativeTo(target, relativeTo)
{
var components = [],
targetParts = target.split("/"),
relativeParts = relativeTo.split("/");
var i = 0;
while (i < targetParts.length)
{
if (targetParts[i] != relativeParts[i])
break;
i++;
}
for (var j = i; j < relativeParts.length; j++)
components.push("..");
for (var j = i; j < targetParts.length; j++)
components.push(targetParts[j]);
return components.join("/");
}
main();