/Tests/DetectMissingImports.js
http://github.com/cacaodev/cappuccino · JavaScript · 224 lines · 176 code · 30 blank · 18 comment · 24 complexity · 6779f7eb36c5e66f8f425a69c6bc19a6 MD5 · raw file
- var FILE = require("file"),
- FileList = require("jake").FileList,
- OS = require("os"),
- stream = require("narwhal/term").stream;
- var cPreprocessedFileContents = function(aFilePath)
- {
- var INCLUDES = new FileList(FILE.join(FILE.dirname(aFilePath), "**", "*.h")).map(function(aFilename)
- {
- return "--include \"" + aFilename + "\"";
- }).join(" ");
- var gcc = OS.popen("gcc -E -x c -P -DPLATFORM_COMMONJS " + INCLUDES + " " + OS.enquote(aFilePath), { charset:"UTF-8" }),
- chunk,
- fileContents = "";
- while (chunk = gcc.stdout.read())
- fileContents += chunk;
-
- return fileContents;
- };
- var checkImportsForFile = function (fileName)
- {
- var classNames = [],
- errorMessageHashSet = {},
- matches = fileName.match(new RegExp("([^\\/]+)\\/([^\\/]+)\\.j$"));
- if (!FILE.exists(fileName) ||
- FILE.isDirectory(fileName) ||
- fileName.indexOf("+") !== -1 ||
- (matches && matches[1] === matches[2]))
- return;
- // this is a hackish way to clear the previous file's @imports
- for (var g in global)
- if (g !== "SyntaxError")
- delete global[g];
- // reload Objective-J and get a reference to its StaticResource export at
- // the same time
- global.StaticResource = require.force("objective-j").StaticResource;
- ObjectiveJ.OBJJ_INCLUDE_PATHS = [FILE.canonical(".")];
- var og_resolveResourceAtURL = StaticResource.resolveResourceAtURL;
- // this function gets called for all "File.j" imports
- // in case the import can't be resolved, use JAKE.FileList to try and find
- // it.
- StaticResource.resolveResourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ isDirectory, /*Function*/ aCallback)
- {
- var og_callback = arguments[2];
- arguments[2] = function (resource)
- {
- if (!resource)
- {
- var basename = FILE.basename(aURL.toString()),
- newURL = (new FileList("Foundation/**/" + basename)).include("AppKit/**/" + basename).items()[0];
- if (newURL)
- return og_resolveResourceAtURL(FILE.canonical(newURL), isDirectory, og_callback)
- else
- og_callback(resource);
- }
- else
- og_callback(resource);
-
- };
- og_resolveResourceAtURL.apply(this, arguments);
- };
- // this function gets called for <Framework/File.j> imports
- // since this script looks at the un-compiled frameworks,
- // some trickery for finding the correct file is sometimes necessary
- var resolveResourceAtURLSearchingIncludeURLs = function (/*CFURL*/ aURL, /*Number*/ anIndex, /*Function*/ aCallback)
- {
- var includeURLs = StaticResource.includeURLs(),
- searchURL = new CFURL(aURL, includeURLs[anIndex]).absoluteURL();
- og_resolveResourceAtURL(searchURL, NO, function(/*StaticResource*/ aStaticResource)
- {
- if (!aStaticResource)
- {
- if (anIndex + 1 < includeURLs.length)
- resolveResourceAtURLSearchingIncludeURLs(aURL, anIndex + 1, aCallback);
- else
- {
- var basename = FILE.basename(aURL),
- newURL = (new FileList("Foundation/**/" + basename)).include("AppKit/**/" + basename).items()[0];
-
- if (newURL)
- resolveResourceAtURLSearchingIncludeURLS(FILE.canonical(newURL), anIndex, aCallback);
- else
- aCallback(NULL);
- }
- return;
- }
- aCallback(aStaticResource);
- });
- }
- StaticResource.resolveResourceAtURLSearchingIncludeURLs = function(/*CFURL*/ aURL, /*Function*/ aCallback)
- {
- resolveResourceAtURLSearchingIncludeURLs(aURL, 0, aCallback);
- };
- // find all the @implementations by running through the CPP and then
- // calling ObjectiveJ.preprocess with a decorated @implementation handler
- // on the Preprocessor
- var fileNameContents = cPreprocessedFileContents(fileName);
- var og_objj_implementation = ObjectiveJ.Preprocessor.prototype.implementation;
- ObjectiveJ.Preprocessor.prototype.implementation = function (tokens)
- {
- var className = tokens.skip_whitespace();
- if (classNames.indexOf(className) === -1)
- classNames.push(className);
- tokens.skip_whitespace(YES);
- og_objj_implementation.apply(this, arguments);
- };
- ObjectiveJ.preprocess(fileNameContents);
- // reset the preprocessor's @implementation handler
- ObjectiveJ.Preprocessor.prototype.implementation = og_objj_implementation;
- // do automatic CPP runs on @imported files
- // to resolve #includes and conditional compilation
- CFHTTPRequest.prototype.responseText = function ()
- {
- if (this._URL.slice(-2) === ".j")
- {
- var tmpFile = FILE.canonical(FILE.join(FILE.dirname(this._URL.split(":")[1]), ".detect_missing_imports"));
- // hackishly give the file a window object
- FILE.write(tmpFile, "window = {};\n" + this._nativeRequest.responseText);
- var result = cPreprocessedFileContents(tmpFile);
- FILE.remove(tmpFile);
- }
- else
- result = this._nativeRequest.responseText;
- return result;
- };
- try
- {
- objj_importFile(FILE.canonical(fileName), YES);
- }
- catch (e)
- {
- if (e.name === "ReferenceError")
- stream.print("\0yellow(Detected missing @import in \"" + fileName + "\": " + e.message + "\0)");
- else
- throw e;
- }
- for(var j = 0, jj = classNames.length; j < jj; ++j)
- {
- var className = classNames[j],
- cls = objj_getClass(className);
- if (cls && cls.super_class)
- {
- // instance methods
- var method_dtable = cls.method_dtable;
- for (var methodName in method_dtable)
- {
- if (method_dtable.hasOwnProperty(methodName))
- {
- try
- {
- var instance = objj_msgSend(cls, "alloc");
- objj_msgSend(instance, methodName, method_dtable[methodName].types.slice(1));
- }
- catch (e)
- {
- if (e.name === "ReferenceError")
- {
- var hashKey = fileName + e.message;
- if (!errorMessageHashSet[hashKey])
- {
- stream.print("\0yellow(Detected missing @import in \"" + fileName + "\": " + e.message + " (Context: [" + className + " " + methodName + "])\0)");
- errorMessageHashSet[hashKey] = true;
- }
- }
- }
- }
- }
- // class methods
- method_dtable = cls.isa.method_dtable;
- for (var methodName in method_dtable)
- {
- if (method_dtable.hasOwnProperty(methodName))
- {
- try
- {
- objj_msgSend(cls, methodName);
- }
- catch (e)
- {
- if (e.name === "ReferenceError")
- {
- var hashKey = fileName + e.message;
- if (!errorMessageHashSet[hashKey])
- {
- stream.print("\0yellow(Detected missing @import in \"" + fileName + "\": " + e.message + " (Context: [" + className + " " + methodName + "])\0)");
- errorMessageHashSet[hashKey] = true;
- }
- }
- }
- }
- }
- }
- }
- };
- (new FileList("Foundation/**.j").include("AppKit/**.j")).forEach(function (aFile)
- {
- checkImportsForFile(aFile);
- });