JSCocoa brings Cocoa to Javascript.
It’s a bridge like PyObjC and RubyCocoa.
Write Cocoa apps in Javascript ! JSCocoa bridges Cocoa to JavascriptCore (WebKit's JS engine). It allows you to call C code, ObjC code, use C structs, and build Javascript classes inheriting from ObjC classes.

Follow JSCocoa updates on Twitter and Ask your questions on the JSCocoa Google Group
2010 03 22Unicode names for classes and selectors I guess JSCocoa is really fully unicode now !

This only works well on the JSCocoa side, as on the ObjC side you'll have to get the class with objc_getClass([@"ファイナンス" UTF8String]). I can't get it to call selectors yet. Still looks nice though !

2009 12 12Catch ObjC exceptions in Javascript Following Rentzsch's post about how JSCocoa was broken, you can now catch ObjC exceptions in Javascript.
try
{
	var outOfRangeObject = [[NSArray arrayWithObjects:@"a", @"b", nil] objectAtIndex:-1]
}
catch(e)
{
	// Prints NSRangeException
	log(e.name)
}
JSCocoa also had a 32bit bug when converting a number to an unsigned int, yielding 0 when converting -1. This is fixed.
2009 10 03Objective-J syntax Trailing Objective-J and JSTalk, JSCocoa has a brand new way to call ObjC methods. This syntax works just like Objective-C, but in Javascript :
// Standard Javascript way
NSApplication.sharedApplication.delegate = myDelegate
// ObjJ way
[[NSApplication sharedApplication] setDelegate:myDelegate]
// Mixed way
[NSApplication sharedApplication].delegate = myDelegate

// Multi param call
var url = [NSURL instanceFileURLWithPath:@"/tmp" isDirectory:true]

// Create a Javascript array containing an NSURL
var array = [[NSURL instanceFileURLWithPath:@"/tmp" isDirectory:true]]
This new syntax is done thanks to JSLint. Because of this, your code needs to conform to JSLint standards — if it doesn't, it won't run. You can disable JSLint (not recommended) with [yourJSCocoa setUseJSLint:NO].

Here's some colored code with lintex :

2009 09 22Explore the Cocoa runtime List loaded classes, protocols, frameworks with these :
  • JSCocoa.classes list all Cocoa classes
  • JSCocoa.protocols all protocols
  • JSCocoa.imageNames all loaded frameworks
List class data with these :
  • MyClass.__subclasses a list of all classes inheriting from MyClass. Use MyClass.__subclassTree for a human readable version
  • MyClass.__classImage name of framework defining the class
  • MyClass.__derivationPath list superclasses
  • MyClass.__methods, MyClass.__ivars, MyClass.__properties, MyClass.__protocols pretty much everything you wanted to know about a class ! These methods list all data from a class and from its superclasses. To get only this class' data, use the own-prefixed methods : MyClass.__ownMethods lists only methods defined by MyClass.
Looking for methods
// Find all NSArray methods starting with 'init'
log(NSArray.__methods.filter(function (method) { return method.name.match(/^init/) }))
// Same code, but only print method name
log(NSArray.__methods.filter(function (method) { return method.name.match(/^init/) }).map(function(o){return o.name}))
// Find NSObject methods defined in the AppKit framework
log(NSObject.__methods.filter(function (method) { return method.framework.match(/AppKit/) } ))
Showing class tree
// Show NSButton superclasses
log('NSButton superclasses=' + NSButton.__derivationPath)
>NSObject,
>NSResponder,
>NSView,
>NSControl,
>NSButton

// Show all CALayer subclasses in human readable form
log('CALayer.subclassTree=\n' + CALayer.__subclassTree)
> CALayer
>  CAEmitterLayer
>  CAGradientLayer
>  CALayerHost
>  CAOpenGLLayer
>   NSOpenGLLayer
>   _NSOpenGLLayer
>  CAReplicatorLayer
(snip)
2009 09 13The new JSTalk website JSTalk is a way to script applications in Javascript. It's built on top of JSCocoa. Give it a try !
2009 09 06Use JSCocoa in place of the existing WebKit bridge The WebKit bridge (isSelectorExcludedFromWebScript, isKeyExcludedFromWebScript,...) lets you call ObjC methods from Javascript. It gets the job done, but has a few limitations : it doesn't bridge hashes and doesn't let you use structures.

By using initWithGlobalContext, JSCocoa can now be used inside a WebView in place of the WebKit bridge. This is the full JSCocoa monty in a webpage, with a small difference : there's a global OSX object to retrieve objects.

// This is JSCocoa called from inside a WebView !
var objCDate = OSX.NSDate.alloc.init
var point = new OSX.NSPoint(123, 456)
var delegate = OSX.NSApplication.sharedApplication.delegate
var array = delegate.testArray( ['hello', 'world', [4, 5, 6], 'end' ] )

Restricting access To prevent the webpage from calling certain methods, use JSCocoa's delegate methods. canGetGlobalProperty, canGetProperty, canCallFunction, canCallMethod will let you write anything from toll free passage to full lockdown.

Check out JSCocoa / WebView sample code, by Fabien Franzen.

2009 09 06x86_64, 64 bit support JSCocoa can now be used in 64 bit applications. Your code should mostly remain intact except for methods dealing with pointers : In 64 bit, CGFloat is now a double, so CGPoint, CGRect, NSColor all use doubles. Therefore when using methods like NSColor.getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha or NSBezierPath.elementAtIndex:(NSInteger)index associatedPoints:(NSPointArray)points, make sure to allocate doubles, not floats.

Call JSCocoa.runningArchitecture to know what you're running on. JSCocoa runs on x86_64, i386, PPC, iPhone and iPhone simulator.

2009 09 01libffi-iphone This is under-the-hood stuff libffi allows calling any C-function or ObjC method at runtime. libffi-iphone is a stripped down version of libffi, tailored just for the iPhone. libffi-iphone includes source code for both the iPhone simulator and the iPhone itself.

JSCocoa uses libffi-iphone internally. You may need it if you're porting a scripting language to the iPhone.

2009 09 01JSCocoa works on the iPhone ! You can now use JSCocoa both on the iPhone and on the Mac. JSCocoa will give you runtime access to ObjC objects and let you call any method of any class. There are a few differences when creating your own ObjC classes in Javascript and when calling C functions, but you can work around these easily.
  • the iPhone has no BridgeSupport files On the Mac, structures, enums, C functions can be used thanks to BridgeSupport files describing them : NSPoint, kCFAllocatorDefault, NSMakeRectRect are read by JSCocoa and made available in the Javascript context. On the iPhone, BridgeSupport files do not exist. You can still use structures, enums, C functions but they must be described in your own BridgeSupport file.
  • the iPhone has no mprotect To create a new ObjC class in Javascript, JSCocoa must create a new ObjC method for each method your overload. These methods are stored in a static pool, but they can be reused by any number of methods at runtime.

Check out the iPhone sample on Github.

JSCocoa works on the iPhone thanks to Philippe Charrière, Tim Burks, Jay Freeman, and Gary Hayenga. Thank you guys !

2009 08 11Safe dealloc You can now safely overload dealloc in your classes. This was previously disabled as objects are deallocated when JavascriptCore triggers Garbage Collection, forbidding any script execution at collect time. To work around that, JSCocoa releases objects on the next run loop cycle, which calls dealloc at a safe time.

This means any binding, notification request made can now be dismissed in dealloc, just like standard ObjC code.

// A class whose targetValue will be bound with Cocoa Bindings
class	BindingsTarget < NSObject
{
	// Dealloc will be called in the next run loop cycle right after JavascriptCore GC
	- (void)dealloc
	{
		this.unbind('targetValue')
	}
	// Declare a targetValue key
	Key targetValue
}

// Instantiate and bind to a source value
var target = BindingsTarget.instance()
target.bind_toObject_withKeyPath_options('targetValue', source, 'sourceValue', null)

2009 08 09Manipulate WebViews with JSCocoa The WebKit bridge allows you to insert your own objects into a web page. JSCocoa now has a reverse bridge of its own, which allows you to manipulate a WebView's document. You can therefore load a web page then query it with code like log(window.document.body.innerHTML). This is done with WebFrame's globalContext.
// Register a load delegate
var loadDelegate = WebViewLoadDelegate.instance()
view.frameLoadDelegate = loadDelegate

// Load a web page
webView.mainFrameURL = 'http://google.com'

// Delegate class
class WebViewLoadDelegate < NSObject
{
	// WebKit will call this method upon page load completion
	- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
	{
		// Global context is frame's window object
		var window = sender.mainFrame.globalContext

		// Change the background color of an element
		window.document.getElementById('someElement').style.backgroundColor = 'lime'

		// Call a Javascript method defined in the page
		window.callSomeJavascriptMethod('hello', 8)
	}
}

2009 08 07JSCocoaLoader allows you to create Espresso actions in Javascript using JSCocoa.

Also check out Narwhal-jsc, a JSCocoa loader for Narwhal (server side Javascript).

Both of them are open source on GitHub.
2009 04 11Swizzle ! JSCocoa now lets you swizzle methods :
class NSButton
{
	// Swizzle an instance method of an existing class
	Swizzle- (void)drawRect:(NSRect)rect
	{
	    // Draw something behind the button
	    ...
	    // Call original swizzled method, this will call NSButton's drawRect:
	    this.Original(arguments)
	    // Draw something in front of the button
	    NSBezierPath.bezierPathWithOvalInRect(rect).stroke
	}
}

swizzling is replacing a method's implementation with our own. This example swizzles NSButton's drawRect: with a Javascript function : each time a button must be drawn, the ObjC runtime will call this Javascript function. If you want to modify the behaviour of existing classes without deriving, swizzling is the way to go ! Thanks to JRSwizzle for the code.

Add Swizzle in front of a method definition to swizzle it. To call the original method, call this.Original(arguments).

2009 03 27Introducing JSTalk, an alternative to AppleScript. Gus Mueller has released the first version of JSTalk, a way to make your application scriptable in Javascript. It also supports an Objective-C syntax.
// JSTalk-enable your application
[JSTalk listen];

// From the JSTalk editor you can then script it in Javascript
var sketch = JSTalk.application("Sketch");
var doc = sketch.orderedDocuments()[0];
var rectangle = doc.makeNewBox();
rectangle.setWidth(100);
rectangle.setHeight(100);

// Or use an ObjC syntax
var bezierPath = [NSBezierPath bezierPath];
[bezierPath curveToPoint:pointA controlPoint1:pointB controlPoint2:pointC];
[bezierPath fill];
Get JSTalk from Github !
2009 03 10Use delegate methods to customize JSCocoa behaviour.
// Check if getting property is allowed
- (BOOL) JSCocoa:(JSCocoaController*)controller 
canGetProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
// Custom handler for getting properties
//	Return a custom JSValueRef to bypass JSCocoa
//	Return NULL to let JSCocoa handle getProperty
//	Return JSValueMakeNull() to return a Javascript null
- (JSValueRef) JSCocoa:(JSCocoaController*)controller 
getProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
These methods allow you to restrict access or customize behaviour. If you want to use JSCocoa as a plugin engine, implement canCallMethod to restrict method call, or canGetProperty and canSetProperty to restrict properties access. canGetGlobalProperty restricts access to ObjC classes, functions, structs and enums.

After restricting access with the can* methods, you can use getProperty, setProperty, callMethod to bypass JSCocoa and implement custom behaviour to return custom values to Javascript.

canLoadJSFile, canEvaluateScript restrict script loading. willEvaluateScript gives you a change to transform the input script before evaluation : use it to implement a custom syntax or expand your own macros.

2009 02 18New class syntax inspired from Cappucino
	// Define a new class
	class MyClass < NSObject
	{
		// instance method
		- (int)addX:(int)x andY:(int)y
		{
			return x + y
		}
		// class method
		+ (float)addFloatX:(float)x andFloatY:(float)y
		{
			return x + y
		}

		// Interface Builder outlet		
		IBOutlet outlet1
		// Interface Builder outlet using a Javacript notification
		IBOutlet outlet2 (newValue)
		{
			log('new value of outlet2=' + newValue)
		}

		// Interface Builder action, using sender as default parameter
		IBAction clickMe
		{
			log('Button clicked=' + sender)
		}
		// Interface Builder action, using custom parameter name
		IBAction clickMeToo(notifier)
		{
			log('Button clicked=' + notifier)
		}
	}
There's some limitations on parameters (right now it's classes, structs, raw int/char/float) but these should go away in the future.
2009 02 18JSLocalizedString defers localization to Javascript functions.
2009 02 13Using Pointers JSCocoa can now handle pointers and memory buffers.
	// Functions like NSOpenGLGetVersion(int*, int*) expect two pointers to int
	// JSCocoa detects pointer types and auto allocs required size
	var major = new outArgument
	var minor = new outArgument
	NSOpenGLGetVersion(major, minor)
	log('OpenGL version : ' + major + '.' + minor)

	// Using with structures
	var rect = new NSRect(10, 20, 30, 40)
	var rect1 = new outArgument
	var rect2 = new outArgument

	NSDivideRect(rect, rect1, rect2, 5, NSMinXEdge)
	log('Divided rect1=' + rect1)

	// Using with ObjC methods : scanning a string with NSScanner
	var scanner = NSScanner.scannerWithString('4.56 123')
	var extractedFloat = new outArgument
	scanner.scanFloat(extractedFloat)
	log('extracted=' + extractedFloat)

	// 
	// Memory buffers : manually allocating memory and using it as data source or sink
	// 

	// Data source : copy color components into our buffer
	// Allocate room for 4 floats
	var buffer = new memoryBuffer('ffff')

	// Extract components of a NSColor into our buffer
	color.get({	red : new outArgument(buffer, 0), 
			green : new outArgument(buffer, 1), 
			blue : new outArgument(buffer, 2),
			alpha : new outArgument(buffer, 3) })
	log('Extracted red=' + buffer[0])

	// Data sink : copy point coordinates into a NSBezierPath element
	// Allocate room for 3 points
	var buffer = new memoryBuffer('ffffff')
	// Set new point values
	buffer[0] = 10.0
	buffer[1] = 5.0
	...
	...

	// Fill a NSBezierPath element with our new coordinates
	path.setAssociatedPoints_atIndex(buffer, 1)
Under the hood, JSCocoaOutArgument and JSCocoaMemoryBuffer handle all this.
2009 02 04Write Cocoa plugins in almost anything Want more than Javascript ? Grayson Hansard wrote PluginManager, a project that enables you to write Cocoa plugins in AppleScript, F-Script, Javascript, Lua, Nu, Python and Ruby. "PluginManager is a series of classes that provides support for a vast number of scripting languages as well as standard Cocoa bundles. It is designed based on AddressBook's applescript plugin support but can be used in a wide number of ways. If nothing else, this project should provide an example into calling of scripts that you can adapt to your own applications."
2009 01 17iPhone libffi Here's a better way than prederivation : Tim Burks advocates a pool of reconfigurable handlers. These handlers can be shared about amongst classes : first, gather the method type encodings from the classes' methods then generate Javascript callbacks from them. Great strategy !
2009 01 16Elysium, a midi sequencer, uses JSCocoa for scripting. Check it out !
2009 01 15iPhone JSCocoa now compiles on the iPhone, thanks to the Nu language's libffi. It crashes because it can't create Javascript methods callable by ObjC. (mprotecting the closure for libffi fails). Looks like there are 3 possibilities :
  • Create an iPhone app and classes in ObjC then use JSCocoa to script these classes
  • Create dummy derived classes with dummy methods each calling their Javascript counterpart
  • Somehow make mprotect work
Any other ideas ? parmanoir@gmail.com
2009 01 12Multiple interpreters support JSCocoa can now create multiple versions of itself, each independant — just like each page in Safari has its interpreter. A document application can host one instance of JSCocoa in each document, each having its own variables separate from the others.
2009 01 10Gus Mueller on JSCocoa and Acorn Plugins in JavaScript
2009 01 08JSCocoa moves to Github Fork, branch, push and pull away !

I love Git, it's really a "what's changed" manager for directories used as source control. Files referenced once will exist only once, files moved will keep refering to the same object, and it's easy to use :
git add . to add the current directory,
git commit -a -m "new version!"; git push to send the new version to Github.
You can tag releases, easily branch from them, all of that locally !

If you don't know git it's worth to spend time to learn how it works. From Github you can fork JSCocoa and the fork queue will show branches and I'll be able to incorporate your changes back in JSCocoa.
2008 12 19Questions/Réponses sur JSCocoa [Developpez]
2008 12 17JSCocoa Google Group Wanna talk about JSCocoa ? There's the place !
2008 12 17JSCocoa as a framework JSCocoa can now be added to an existing project as a framework — much simpler that before ! Checkout the latest version from svn.
2008 12 11JSCocoa Garbage Collection
2008 11 28JSCocoa Core Animation sample code
2008 11 22JSCocoa interactive console for iPhone written by Kumagai Kentaro
2008 10 24JSCocoa working on iPhone simulator — check it out via svn
2008 10 15Advice ? on JSCocoa iPhone
2008 10 15Updated documentation
2008 10 14Questions/Réponses sur JSCocoa [Cocoa.fr]
2008 10 10Command line interpreter and REPL for JSCocoa written by Tom Robinson
2008 10 08Initial release
Everywhere dot
Just like in Ruby, call functions with or without parentheses. object.a().b().c() becomes object.a.b.c
Alas, if (a.b.c) won't work — use if (a.b.c()) until toBoolean() arrives
CocoaNSString* appName = [[[NSWorkspace sharedWorkspace] activeApplication] valueForKey:@"NSApplicationName"];
JSCocoavar appName = NSWorkspace.sharedWorkspace.activeApplication.NSApplicationName
Instance
Tired of the alloc/init dance ? Use instance to get an object allocated, inited, and retained by Javascript's Garbage Collector
Cocoa [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 40)];
Need to [ release] when done
JSCocoa NSButton.alloc.initWithFrame(NSMakeRect(0, 0, 100, 40))
Need to release() when done
NSButton.instance({ withFrame:NSMakeRect(0, 0, 100, 40) })
Handled by Javascript's GC
Get/Set
Instead of calling setVariable(newValue), use Javascript's setter syntax : object.variable = newValue
Cocoa NSString* title = [window title];
[window setTitle:@"Hello !"];
JSCocoa var title = window.title
window.title = 'Hello !'
Call
Use a jQuery-like syntax to call multiple parameter methods
Cocoa [obj callWithParam1:@"Hello" andParam2:"World"];
JSCocoa obj.call({ withParam1:'Hello', andParam2:'World' })
obj['callWithParam1:andParam2:']('Hello', 'World')
obj.callWithParam1_andParam2('Hello', 'World' )
Fully Unicode
Name your variables in your native language !
JSCocoa function 追加する(最初の, 次の) { return 最初の+ 次の }
var 結果 = 追加する('こんにちは', '世界')
NSApplication.sharedApplication.keyWindow.title = 結果
Derive
A hash will define classes in one go, but you can add methods anytime after
Cocoa In .h @interface MyButton : NSButton { IBOutlet NSButton* myOutlet; } - (IBAction)myAction:(id)sender; @end In .m @implementation MyButton - (IBAction)myAction:(id)sender { ... } @end
JSCocoa defineClass('MyButton < NSButton', { myOutlet : 'IBOutlet' ,myAction : ['IBAction', function (sender) { ... }] })
Shorthand Overload
A quick way to overload methods : define a new class, use NSClass[method] = fn to overload methods like drawRect:
To call the parent method, one single syntax : this.Super(arguments) — no need to rewrite the method name !
JSCocoa MyButtonClass['drawRect:'] = function(rect) { // super call this.Super(arguments) // Add some custom drawing ... }
Integrate in Interface Builder
There's a catch here !
JSCocoa works with NIBs, but you'll need to manually add IBOutlets and IBActions while creating your interface. If you've ever wondered why there are + and - buttons in the Identity Inspector, wonder no more ! :)
Check it out — it's open
Wanna check in ? Mail me at parmanoir@gmail.com for write access.
Visit JSCocoa on Google Code, or check it out via Git :

git clone git://github.com/parmanoir/jscocoa.git