Blog

Make A JavaScript Formatter with V8 and jsbeautifier

If you're a JavaScript developer, you should check out a handy online tool called jsbeautifier.org, written by Einar Lielmanis. By simply pasting your JavaScript code and clicking Beautify, the jsbeautifier tool automatically reformats and reindents your JavaScript code (or JSON snippets) based on spacing, packing, and other options that you can configure.
A great feature of jsbeautifier is that the formatter has a JavaScript API (check it out here http://github.com/einars/js-beautify/), whose simple API call is js_beautify(js_source_text, options). This returns the formatted version of js_source_text based on the settings passed in in options.
If you want to programmatically “beautify” local files, you can also run the jsbeautifier script from the command line. There is support for Rhino, a JavaScript interpreter written in Java, to invoke the beautifier with the content of any file. Or if you'd prefer to not use Rhino, I recently added support for Qt Script or V8. Qt Script is the JavaScript engine built into Qt, the multi-platform application framework from Nokia. V8 is the JavaScript engine that powers Google Chrome.
In one of my previous blog posts, JavaScript Engines: How to Compile Them, I discussed how JavaScript engines can do more than just power a web browser. Today, I'll use the V8-based beautifier as an example of how to embed V8 in a command-line application.

Note: We're using V8 version 2.4.9 (revision 5610), earlier or later versions may have slightly different APIs.
When you've successfully compiled V8, you will get a static library: lib/libv8.a.
Next, compile the beautifer:

g++ -o jsbeautify jsbeautify.cpp -Ilib/include/ -lv8 -Llib

The resulting executable jsbeautify is the final tool. Just place jsbeautify in your PATH to use it.
Now, you can set up your text editor to launch jsbeautify as an external application, and you have a handy auto-formatter!
Try out the tool by passing a file name as the argument, and the beautified contents will be printed out:

./jsbeautify hello.js

You can use the --overwrite option if you want to overwrite the original file.

How It Works

You'll need a little background in C++ to understand the following code snippets (since V8 is written in C++). And to follow everything perfectly, you should also read the Getting Started Guide To V8 and the V8 Embedder's Guide.
This is the annotated version of our tool:

The first thing the program does is read the input file (the name is passed as an argument to the program) and load the contents to a buffer (allocated from the heap). Nothing fancy here, just basic I/O (written for simplicity). Obviously, the buffer lives in the C++ world, so we need to transfer it to the JavaScript world so it can be accessed by the beautifier function.

As mentioned in the V8 Embedder's Guide, to use V8, we have to prepare a handle scope, a global object, and an execution context. To pass the buffer content from C++ to JavaScript, we set the property called 'code' in our global object to point to a new String object initialized with the buffer content. From this point, any JavaScript code running in the context can refer to and get the value of ‘code’.

Context needs to be entered before we can use it, this is easily achieved using the context scope. After that, we compile the script which actually implements the js_beautify function and then immediately evaluate it.

At this stage, the JavaScript context already has access to an object (which is actually a string) named ‘code’ and a function ‘js_beautify’. So now we just need to connect the dots: evaluate “js_beautify(code)” and get the result. We also need to transfer the result, which still lives in the JavaScript world, back to our application’s C++ world:

The final step is to print it out. And that’s all!
This example shows how you can quickly use V8 to wrap and execute a JavaScript function and turn it into a real-world tool. I hope it serves as a good start for you to explore the features of V8 as an embedded scripting engine!

Written by Ariya Hidayat
Ariya is a passionate technologist and open-source advocate with over a decade of experience dealing with different varieties of hardware and software. These days his focus is mainly on web technologies. He is a WebKit reviewer and has been contributing to WebKit in the last 3 years.Follow Ariya on Twitter

Enc

I would like to respectfully disagree with anyone who thinks that this article is in any way close to “cool”.
A _cool_ article or, in other words, a useful, informative and insightful article, would actually contain information that is more useful than a stub page on Wikipedia.

This article teaches ‘JavaScript’ developers who supposedly don’t know any better or are not that good with C++ that it’s not such a bad idea to create a command line tool in C++ that embeds a JavaScript interpreter written in C++ to run a JavaScript parser script written in JavaScript to format JavaScript code.

Well, I have news for you: that is not in any way _cool_ or useful. In fact, it’s redundant, unnecessary, a misuse of jsbeautifier and a waste of resources.

To see why, let’s take this article even further in ridiculousness. So far we’ve got a command line tool embedding V8 to run a JS script that parses JS code and outputs the result. Now, create a virtual machine to virtualize this tool and host the VM on Amazon, provide a REST API for your users to POST their code with curl and pipe the XML output to an XSLT processor which will use an XSL stylesheet to format the XML and transform it back to properly indented and colorized JavaScript.

If you still think that the above is _cool_ and not outrageous, then you have failed.

Obviously, one might argue that the goal was to show how to embed V8 and run some JavaScript code in it. In that case, I still question the usefulness of this article, since it could have been simply reduced to the following sentence: “RTFM @ http://code.google.com/apis/v8/embed.html”.

A more useful article for creating a command-line JavaScript “beautifier” using V8 would have been one that explains how to reuse functionality from V8 (mainly the parse tree I imagine it must construct) to print properly indented and highlighted JavaScript code, without actually wasting resources on interpreting any of it.

Overall, I say 100/100 for the good intentions and initiative, but a 50/100 for the content.