mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-05 16:42:58 +00:00
add script to automatically detect missing @imports and have it run from "jake test-only"
This commit is contained in:
1 parent
12deb6859e
commit
3287b02816
2 files changed
+222
No files matched your search
@@ -263,6 +263,8 @@ task("test-only", function()
|
||||
var code = OS.system(serializedENV() + " " + cmd.map(OS.enquote).join(" "));
|
||||
if (code !== 0)
|
||||
OS.exit(code);
|
||||
|
||||
OS.system(serializedENV() + " " + ["js", "Tests/DetectMissingImports.js"].map(OS.enquote).join(" "));
|
||||
});
|
||||
|
||||
task("push-packages", ["push-cappuccino", "push-objective-j"]);
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
var FILE = require("file"),
|
||||
FileList = require("jake").FileList,
|
||||
OS = require("os"),
|
||||
stream = require("narwhal/term").stream;
|
||||
|
||||
var cPreprocessedFileContents = function(aFilePath)
|
||||
{
|
||||
var gcc = OS.popen("gcc -E -x c -P -DPLATFORM_COMMONJS " + 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);
|
||||
});
|
||||
Reference in new issue
Block a user