diff --git a/CommonJS/bin/flatten b/CommonJS/bin/flatten index 3af4d64fa..d98ff8466 100755 --- a/CommonJS/bin/flatten +++ b/CommonJS/bin/flatten @@ -87,10 +87,7 @@ function main(args) flattener.load(mainPath); flattener.finishLoading(); - var applicationRoot = flattener.require("objective-j").StaticResource.resourceAtURL(rootPath) - print(applicationRoot.toString()); - - var applicationJS = flattener.buildApplicationJS(applicationRoot); + var applicationJS = flattener.buildApplicationJS(); FILE.copyTree(rootPath, outputPath); @@ -103,7 +100,9 @@ function main(args) function ObjectiveJFlattener(rootPath) { ObjectiveJRuntimeAnalyzer.apply(this, arguments); - this.resourceBuffer = []; + this.fileCacheBuffer = []; + + this.staticResourceBuffer = []; this.bundleBuffer = []; this.functionsBuffer = []; @@ -112,110 +111,118 @@ function ObjectiveJFlattener(rootPath) { ObjectiveJFlattener.prototype = Object.create(ObjectiveJRuntimeAnalyzer.prototype); -ObjectiveJFlattener.prototype.buildApplicationJS = function(applicationRoot) { - this.serializeStaticResources(applicationRoot); - this.serializeStaticFileExecutables(); +ObjectiveJFlattener.prototype.buildApplicationJS = function() { - var buffer = [] + this.serializeFunctions(); + this.serializeFileCache(); - buffer.push("(function(){"); - - buffer.push("var appURL = new CFURL('.', ObjectiveJ.pageURL);") - - buffer.push(this.bundleBuffer.join("\n")); - - buffer.push("var nodeStack = [];"); - buffer.push("var applicationRoot = ObjectiveJ.StaticResource.resourceAtURL(appURL, true);"); - buffer.push("var currentNode = null;"); - buffer.push("var newNode;"); - - buffer.push(this.resourceBuffer.join("\n")); - - buffer.push("})();"); + var buffer = []; + buffer.push("var baseURL = new CFURL(\".\", ObjectiveJ.pageURL);"); + buffer.push(this.fileCacheBuffer.join("\n")) buffer.push(this.functionsBuffer.join("\n")); - buffer.push("ObjectiveJ.bootstrap();"); return buffer.join("\n"); } -ObjectiveJFlattener.prototype.serializeStaticFileExecutables = function() { - this.require("objective-j").FileExecutable.allFileExecutables().forEach(function(aFileExecutable) { - var deps = aFileExecutable.fileDependencies().map(function(dependency) { - return "new ObjectiveJ.FileDependency(new CFURL("+JSON.stringify(dependency.path())+"),"+JSON.stringify(dependency.isLocal())+")" - }).join(","); +ObjectiveJFlattener.prototype.serializeFunctions = function() { + var inlineFunctions = true;//this.options.inlineFunctions; - var func = aFileExecutable._function.toString(); - // HACK - func = func.replace(", require, exports, module, system, print, window", ""); + var outputFiles = {}; - this.functionsBuffer.push("var path = "+JSON.stringify(this.rootPath.relative(aFileExecutable.path()).toString())+";"); - this.functionsBuffer.push("new ObjectiveJ.FileExecutable(path,"+ - "new ObjectiveJ.Executable(null, ["+deps+"], path, "+func+"));"); + var _cachedExecutableFunctions = {}; + + this.require("objective-j").FileExecutable.allFileExecutables().forEach(function(executable) { + var path = executable.path(); + + if (inlineFunctions) + { + // stringify the function, replacing arguments + var functionString = executable._function.toString().replace(", require, exports, module, system, print, window", ""); // HACK + + var relative = this.rootPath.relative(path).toString(); + this.functionsBuffer.push("ObjectiveJ.FileExecutable._cacheFunction(new CFURL("+JSON.stringify(relative)+", baseURL), "+functionString+");"); + } + + var bundle = this.context.global.CFBundle.bundleContainingURL(path); + if (bundle && bundle.infoDictionary()) + { + var executablePath = bundle.executablePath(), + relativeToBundle = FILE.relative(FILE.join(bundle.path(), ""), path); + + if (executablePath) + { + if (inlineFunctions) + { + // remove the code since we're inlining the functions + executable._code = "alert("+JSON.stringify(relativeToBundle)+");"; + } + + if (!outputFiles[executablePath]) + { + outputFiles[executablePath] = []; + outputFiles[executablePath].push("@STATIC;1.0;"); + } + + var fileContents = executable.toMarkedString(); + + outputFiles[executablePath].push("p;" + relativeToBundle.length + ";" + relativeToBundle); + outputFiles[executablePath].push("t;" + fileContents.length + ";" + fileContents); + + // stream.print("Adding \0green(" + this.rootPath.relative(path) + "\0) to \0cyan(" + this.rootPath.relative(executablePath) + "\0)"); + } + } + else + CPLog.warn("No bundle (or info dictionary for) " + rootPath.relative(path)); }, this); + + for (var executablePath in outputFiles) + { + var relative = this.rootPath.relative(executablePath).toString(); + var contents = outputFiles[executablePath].join(""); + this.fileCacheBuffer.push("CFHTTPRequest._cacheRequest(new CFURL("+JSON.stringify(relative)+", baseURL), 200, {}, "+JSON.stringify(contents)+");"); + } } -ObjectiveJFlattener.prototype.serializeStaticResources = function(node, depth) { - depth = depth || 0; - - var bundle = this.context.global.CFBundle.bundleContainingURL(node.URL()); - var bundlePath; - if (!bundle) { - stream.print("\0yellow(Warning:\0) No bundle for path: \0cyan("+node.URL()+"\0)"); - } - else if ((bundlePath = bundle.bundlePath()) && !this._outputBundles[bundlePath]) { - this._outputBundles[bundlePath] = bundle; - stream.print("Writing bundle: \0cyan("+bundlePath+"\0)"); - print(bundle.infoDictionary()) - - var relative = this.rootPath.relative(bundlePath).toString(); - this.bundleBuffer.push("var bundle = new CFBundle("+ - "new CFURL("+(relative ? JSON.stringify(relative) : "appURL")+", ObjectiveJ.pageURL)"+ - ");"); - this.bundleBuffer.push("bundle._loadStatus = " + (1<<4) + ";"); - this.bundleBuffer.push("bundle._isValid = true;"); - if (bundle.infoDictionary()) { - this.bundleBuffer.push("bundle._infoDictionary = CFPropertyList.propertyListFromString(" + - JSON.stringify(CPPropertyListCreateData(bundle.infoDictionary()).rawString()) + ");"); +ObjectiveJFlattener.prototype.serializeFileCache = function() { + Object.keys(this.requestedURLs).forEach(function(absolute) { + var relative = this.rootPath.relative(absolute).toString(); + if (relative.indexOf("..") === 0) + { + print("skipping (parent of app root): " + absolute); + return; } - } - // not the root node: - if (depth > 0) { - this.resourceBuffer.push("newNode = new ObjectiveJ.StaticResource(new CFURL(" + - JSON.stringify(node.name()) + "," + - "currentNode.URL().asDirectoryPathURL()" + - "), currentNode, " + - JSON.stringify(node.isDirectory()) + ", " + - JSON.stringify(node.isResolved()) + ");"); - } else { - this.resourceBuffer.push("newNode = applicationRoot;"); - } + if (FILE.isFile(absolute)) + { + if (FILE.extension(absolute) === ".sj") + { + print("skipping (bundle executable): " + absolute); + return; + } + // if (this.options.maxCachedSize && FILE.size(absolute) > this.options.maxCachedSize) + // { + // print("skipping (larger than "+this.options.maxCachedSize+" bytes): " + absolute); + // return; + // } - // var contents = node.contents(); - // if (contents) { - // this.resourceBuffer.push("newNode._contents = " + JSON.stringify(contents) + ";"); - // } - - if (!node.children()) - return; - - this.resourceBuffer.push("nodeStack.push(currentNode);"); - this.resourceBuffer.push("currentNode = newNode;"); - - var children = node.children(); - for (var name in children) { - this.serializeStaticResources(children[name], depth+1); - } - - this.resourceBuffer.push("currentNode = nodeStack.pop();"); + print("caching: " + absolute); + var contents = FILE.read(absolute, { charset : "UTF-8" }); + this.fileCacheBuffer.push("CFHTTPRequest._cacheRequest(new CFURL("+JSON.stringify(relative)+", baseURL), 200, {}, "+JSON.stringify(contents)+");"); + } else { + this.fileCacheBuffer.push("CFHTTPRequest._cacheRequest(new CFURL("+JSON.stringify(relative)+", baseURL), 404);"); + } + }, this); } // "$1" is the matching indentation var scriptTagsBefore = '$1'; var scriptTagsAfter = '$1'; +// enable CPLog: +// scriptTagsAfter = '$1\n' + scriptTagsAfter; + function rewriteMainHTML(indexHTMLPath) { if (indexHTMLPath.isFile()) { var indexHTML = indexHTMLPath.read(); diff --git a/CommonJS/lib/cappuccino/objj-analysis-tools.j b/CommonJS/lib/cappuccino/objj-analysis-tools.j index 428262391..49e40e8d4 100644 --- a/CommonJS/lib/cappuccino/objj-analysis-tools.j +++ b/CommonJS/lib/cappuccino/objj-analysis-tools.j @@ -5,6 +5,8 @@ var Context = require("interpreter").Context; ObjectiveJRuntimeAnalyzer = function(rootPath) { this.rootPath = rootPath; + this.rootURL = new CFURL(String(rootPath)); + this.context = new Context(); this.scope = setupObjectiveJ(this.context); @@ -28,6 +30,14 @@ ObjectiveJRuntimeAnalyzer = function(rootPath) var url = this.executableURL(); return url ? url.absoluteURL().path() : null; } + + var requestedURLs = this.requestedURLs = {}; + var _lookupCachedRequest = this.context.global.CFHTTPRequest._lookupCachedRequest; + this.context.global.CFHTTPRequest._lookupCachedRequest = function(aURL) { + var path = new CFURL(aURL, this.rootURL).absoluteURL().path(); + requestedURLs[path] = true; + return _lookupCachedRequest.apply(null, arguments); + } } ObjectiveJRuntimeAnalyzer.prototype.setIncludePaths = function(includePaths) {