diff --git a/Electrino/Electrino.xcodeproj/project.pbxproj b/Electrino/Electrino.xcodeproj/project.pbxproj index 87cadd1..0903bfc 100644 --- a/Electrino/Electrino.xcodeproj/project.pbxproj +++ b/Electrino/Electrino.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 5AA9DBED1EBA55B700EF7CC9 /* ENOJSProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AA9DBEC1EBA55B700EF7CC9 /* ENOJSProcess.m */; }; 5AA9DBF01EBA564600EF7CC9 /* ENOJSConsole.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AA9DBEF1EBA564600EF7CC9 /* ENOJSConsole.m */; }; 5AA9DBF21EBA7C0700EF7CC9 /* ENOBrowserWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5AA9DBF11EBA7C0700EF7CC9 /* ENOBrowserWindowController.xib */; }; + BC44C7D01EBF2D0E008C569A /* app in Resources */ = {isa = PBXBuildFile; fileRef = BC44C7CF1EBF2D0E008C569A /* app */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -65,9 +66,6 @@ 5AA9DBBC1EB9F58B00EF7CC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5AA9DBC21EBA08BE00EF7CC9 /* ENOBrowserWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ENOBrowserWindowController.h; sourceTree = ""; }; 5AA9DBC31EBA08BF00EF7CC9 /* ENOBrowserWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ENOBrowserWindowController.m; sourceTree = ""; }; - 5AA9DBC81EBA0BDD00EF7CC9 /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; - 5AA9DBC91EBA0BDD00EF7CC9 /* main.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = main.js; sourceTree = ""; }; - 5AA9DBCA1EBA0BDD00EF7CC9 /* package.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = package.json; sourceTree = ""; }; 5AA9DBD21EBA0D1200EF7CC9 /* ENOJavaScriptApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ENOJavaScriptApp.h; sourceTree = ""; }; 5AA9DBD31EBA0D1200EF7CC9 /* ENOJavaScriptApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ENOJavaScriptApp.m; sourceTree = ""; }; 5AA9DBDC1EBA4F7B00EF7CC9 /* ENOJSPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ENOJSPath.h; sourceTree = ""; }; @@ -83,6 +81,7 @@ 5AA9DBEE1EBA564600EF7CC9 /* ENOJSConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ENOJSConsole.h; sourceTree = ""; }; 5AA9DBEF1EBA564600EF7CC9 /* ENOJSConsole.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ENOJSConsole.m; sourceTree = ""; }; 5AA9DBF11EBA7C0700EF7CC9 /* ENOBrowserWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ENOBrowserWindowController.xib; sourceTree = ""; }; + BC44C7CF1EBF2D0E008C569A /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -110,8 +109,8 @@ 5AA9DBA51EB9F58A00EF7CC9 = { isa = PBXGroup; children = ( + BC44C7CF1EBF2D0E008C569A /* app */, 5A3C03301ECCDC8700643964 /* test-tray */, - 5AA9DBC71EBA0BDD00EF7CC9 /* test-app */, 5AA9DBB01EB9F58A00EF7CC9 /* Electrino */, 5AA9DBAF1EB9F58A00EF7CC9 /* Products */, ); @@ -152,16 +151,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 5AA9DBC71EBA0BDD00EF7CC9 /* test-app */ = { - isa = PBXGroup; - children = ( - 5AA9DBC81EBA0BDD00EF7CC9 /* index.html */, - 5AA9DBC91EBA0BDD00EF7CC9 /* main.js */, - 5AA9DBCA1EBA0BDD00EF7CC9 /* package.json */, - ); - path = "test-app"; - sourceTree = ""; - }; 5AA9DBD51EBA4D8500EF7CC9 /* JS API implementations */ = { isa = PBXGroup; children = ( @@ -197,7 +186,6 @@ 5AA9DBAA1EB9F58A00EF7CC9 /* Sources */, 5AA9DBAB1EB9F58A00EF7CC9 /* Frameworks */, 5AA9DBAC1EB9F58A00EF7CC9 /* Resources */, - 5AA9DBCE1EBA0BEA00EF7CC9 /* CopyFiles */, ); buildRules = ( ); @@ -246,6 +234,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BC44C7D01EBF2D0E008C569A /* app in Resources */, 5AA9DBB81EB9F58B00EF7CC9 /* Assets.xcassets in Resources */, 5AA9DBF21EBA7C0700EF7CC9 /* ENOBrowserWindowController.xib in Resources */, 5AA9DBBB1EB9F58B00EF7CC9 /* MainMenu.xib in Resources */, diff --git a/Electrino/Electrino/ENOJavaScriptApp.m b/Electrino/Electrino/ENOJavaScriptApp.m index c2e44fc..7ffc084 100644 --- a/Electrino/Electrino/ENOJavaScriptApp.m +++ b/Electrino/Electrino/ENOJavaScriptApp.m @@ -90,9 +90,48 @@ - (id)init [weakSelf _jsException:exception]; }; - self.jsContext[@"require"] = ^(NSString *arg) { - id module = weakSelf.jsModules[arg]; - return module; + self.jsContext[@"require"] = ^(NSString *arg) { + + NSString *appDir = [[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"app"] stringByAppendingString:@"/"]; + + if ([arg hasSuffix:@".js"]) { // If a javascript file is being directly referenced + JSContext *tmpContext = [weakSelf newContextForEvaluation]; + + [tmpContext evaluateScript:[NSString stringWithContentsOfURL:[NSURL fileURLWithPath:[appDir stringByAppendingString:arg]] encoding:NSUTF8StringEncoding error:NULL]]; + JSValue *module = tmpContext[@"module"]; + return (id)[module valueForProperty:@"exports"]; // Casted to id as the compile doesn't like multiple types of return values when no return value is specified + } else if (weakSelf.jsModules[arg] != nil) { + id module = weakSelf.jsModules[arg]; + return module; + } + + BOOL isDirectory; + BOOL doesExist = [[NSFileManager defaultManager] fileExistsAtPath:[appDir stringByAppendingString:arg] isDirectory:&isDirectory]; + if (doesExist && isDirectory) { + // Find where the starting point is within package.json + NSData *packageJSON = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[appDir stringByAppendingString:arg] stringByAppendingString:@"/package.json"]]]; + if (packageJSON == nil) { + return (id)nil; + } + NSDictionary *packageDictionary = [NSJSONSerialization JSONObjectWithData:packageJSON options:0 error:NULL]; + if (packageDictionary == nil || packageDictionary[@"main"] == nil) { + return (id)nil; + } + NSString *mainJSFile = packageDictionary[@"main"]; + NSURL *fileURL = [NSURL fileURLWithPath:packageDictionary[@"main"] relativeToURL:[NSURL fileURLWithPath:[appDir stringByAppendingString:arg]]]; + mainJSFile = [@"/" stringByAppendingString:mainJSFile]; + NSString *jsFileContents = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:NULL]; + + JSContext *tmpContext = [weakSelf newContextForEvaluation]; + + [tmpContext evaluateScript:jsFileContents]; + JSValue *module = tmpContext[@"module"]; + return (id)[module valueForProperty:@"exports"]; // Casted to id as the compile doesn't like multiple types of return values when no return value is specified + } else { + // Module doesn't exist! + } + return (id)nil; + }; self.jsContext[@"process"] = [[ENOJSProcess alloc] init]; @@ -101,6 +140,18 @@ - (id)init return self; } +// Create a new context for just evaluating the file +// ISSUE: JSContext does not include -copyWithZone: method, so we have to manually copy the required methods. +-(JSContext*)newContextForEvaluation +{ + JSContext* newContext = [[JSContext alloc] initWithVirtualMachine:self.jsVM]; + newContext[@"require"] = self.jsContext[@"require"]; + newContext[@"process"] = self.jsContext[@"process"]; + newContext[@"console"] = self.jsContext[@"console"]; + [newContext evaluateScript:@"var exports = {}; var module = { exports }"]; // Evaluated so the developer doesnt have to + return newContext; +} + - (void)dealloc { self.jsContext.exceptionHandler = NULL; @@ -142,7 +193,7 @@ - (BOOL)loadMainJS:(NSString *)js error:(NSError **)outError } return NO; // -- } - + NSLog(@"%s done", __func__); return YES; diff --git a/Electrino/test-app/index.html b/Electrino/app/index.html similarity index 100% rename from Electrino/test-app/index.html rename to Electrino/app/index.html diff --git a/Electrino/test-app/main.js b/Electrino/app/main.js similarity index 87% rename from Electrino/test-app/main.js rename to Electrino/app/main.js index 5dce59b..81eb245 100644 --- a/Electrino/test-app/main.js +++ b/Electrino/app/main.js @@ -50,3 +50,11 @@ app.on('activate', () => { createWindow() } }) + +const module_simple = require('module.js') +module_simple.custom_function(); + +const module_folder = require('module_folder') +module_folder.custom_function(); + +const module_exports = require('module_exports.js')(); diff --git a/Electrino/app/module.js b/Electrino/app/module.js new file mode 100644 index 0000000..9410927 --- /dev/null +++ b/Electrino/app/module.js @@ -0,0 +1,5 @@ +function custom_function() { + console.log("Function from a module!"); +} + +exports.custom_function = custom_function; diff --git a/Electrino/app/module_exports.js b/Electrino/app/module_exports.js new file mode 100644 index 0000000..a085dd5 --- /dev/null +++ b/Electrino/app/module_exports.js @@ -0,0 +1,3 @@ +module.exports = function () { + console.log("Function from a module overwriting module.exports!"); +} diff --git a/Electrino/app/module_folder/lib/main.js b/Electrino/app/module_folder/lib/main.js new file mode 100644 index 0000000..1916274 --- /dev/null +++ b/Electrino/app/module_folder/lib/main.js @@ -0,0 +1,5 @@ +function custom_function() { + console.log("Function from a module within a folder!"); +} + +exports.custom_function = custom_function; diff --git a/Electrino/app/module_folder/package.json b/Electrino/app/module_folder/package.json new file mode 100644 index 0000000..18e13fd --- /dev/null +++ b/Electrino/app/module_folder/package.json @@ -0,0 +1,6 @@ +{ + "name": "module_folder", + "version": "0.0.1", + "description": "Testing modules in folders!", + "main": "./lib/main.js" +} diff --git a/Electrino/test-app/package.json b/Electrino/app/package.json similarity index 100% rename from Electrino/test-app/package.json rename to Electrino/app/package.json