{"id":783,"date":"2012-08-01T23:01:20","date_gmt":"2012-08-01T23:01:20","guid":{"rendered":"http:\/\/joelinoff.com\/blog\/?p=783"},"modified":"2026-06-28T17:38:21","modified_gmt":"2026-06-29T00:38:21","slug":"installing-jshint-and-rhino-for-command-line-javascript-analysis","status":"publish","type":"post","link":"https:\/\/joelinoff.com\/blog\/?p=783","title":{"rendered":"Installing jshint and rhino for command line javascript analysis"},"content":{"rendered":"I recently had to install jshint and rhino. It was a bit of a challenge because they needed ant and npm (node package manager). This blog describes what I did and provides a bash shell script that you can use. \n<!--more-->\nJshint (<a href=\"http:\/\/www.jshint.com\">http:\/\/www.jshint.com<\/a>) is a tool that allows you to statically analyze javascript code. It is useful for detecting ertors and enforcing coding standards.\n\nRhino is a command line interpreter for javascript (<a href=\"http:\/\/mozilla.org\/rhino\">http:\/\/mozilla.org\/rhino<\/a>) that is written in java. It can be used for testing and for server side implementations.\n\nYou do not have to be root to install these tools.\n<h1>1 Download<\/h1>\nHere are the links to the project code:\n<table>\n<thead>\n<tr><td>Archive<\/td><td>Size<\/td><td>Extract Command<\/td><\/tr>\n<\/thead>\n<tbody>\n<tr><td><a href=\"http:\/\/downloads.joelinoff.com\/jsdev.tar.bz2\">jsdev.tar.bz2<\/a><\/td><td>4.6K<\/td><td><code>tar jxf jsdev.tar.bz2<\/code><\/td><\/tr>\n<tr><td><a href=\"http:\/\/downloads.joelinoff.com\/jsdev.tar.gz\">jsdev.tar.gz<\/a><\/td><td>4.6K<\/td><td><code>tar zxf jsdev.tar.gz<\/code><\/td><\/tr>\n<tr><td><a href=\"http:\/\/downloads.joelinoff.com\/jsdev.zip\">jsdev.zip<\/a><\/td><td>6.0K<\/td><td><code>unzip jsdev.zip<\/code><\/td><\/tr>\n<\/tbody>\n<\/table>\n<h1>2 Extract<\/h1>\nUse the appropriate command from the previous to table to extract the contents of the archive. When you are finished it will look like this:\n<table><tbody><tr><td>\n<code>jsdev\/Makefile\njsdev\/conf\/std.conf\njsdev\/tests\/test.sh\njsdev\/tests\/test01.js\njsdev\/tests\/test02.js\njsdev\/setup.sh<\/code><\/td><\/tr><\/tbody><\/table>\n<h1>3 Build<\/h1>\nBuild the system using <code>make<\/code>. It requires you to have make and java to be installed.\n\nWhen the build it complete, the tools will be in jsdev\/rtf\/bin directory. You will need to add this directory to your path environment variable as shown in next section to use the tools.\n<h1>4 Usage<\/h1>\nThe example below takes you through the entire process of downloading, installing and using the tools.\n\n<pre class=\"wp-block-code language-bash\"><code class=\"language-bash\">$ bash -version\n$ mkdir \/home\/me\/work\n$ cd \/home\/me\/work\n$ wget http:\/\/downloads.joelinoff.com\/jsdev.tar.bz2\n&lt;output snipped&gt;\n$ tar jxf jsdev.tar.bz2\n&lt;output snipped&gt;\n$ rm -f jsdev.tar.bz2\n$ cd jsdev\n$ make\n&lt;output snipped&gt;\n$ export PATH=\"\/home\/me\/work\/rtf\/bin:${PATH}\"\n$ which jshint\n\/home\/me\/work\/rtf\/bin\/jshint\n$ which rhino\n\/home\/me\/work\/rtf\/bin\/rhino\n$ rhino -e 'print(\"hello, world!\");'\nhello, world!\n$ cat &gt;test.js &lt;&lt;EOF\n\/\/ Contains intentional errors.\n\n\/\/ Missing semi-colon:\nvar x=42\n\n\/\/ Bad conditional expression:\nif (x=2) {\n    print('GOOD');\n}\nEOF\n$ jshint test.js\n\/tmp\/x.js: line 4, col 9, Missing semicolon.\n\/tmp\/x.js: line 7, col 6, Expected a conditional expression and instead saw an assignment.\n\n2 errors\n$ <\/code><\/pre>\n\n<h1>5 Trouble Shooting<\/h1>\nI have only tested this on a CentOS 5.5 system.\n\nIf something goes wrong, take a look at the setup.sh script. It is most likely because there are some packages missing.\n\nFurthermore, you can remove the sections for ant and\/or npm if you already have them installed.\n<h1>6 Manual Steps<\/h1>\nHere are the manual steps.\n<ol>\n\t<li>Install ant.<\/li>\n\t<li>Install npm (node).<\/li>\n\t<li>Install jshost using npm.<\/li>\n\t<li>Install rhino using ant.<\/li>\n\t<li>Create the rhino tool.<\/li>\n<\/ol>\n\n<blockquote>If you want to install in a directory like \/usr\/local\/bin change the rtf variable assignment at line 43.<\/blockquote>\n\n\n<pre class=\"wp-block-code language-bash\"><code class=\"language-bash\">#!\/bin\/bash\n\n# Make a complete javascript test environment consisting\n# of rhino and jshint.\n\n# ================================================================\n# Useful command.\n# ================================================================\nfunction docmd() {\n    local cmd=\"$*\"\n    echo\n    echo \"# ================================================================\"\n    echo \"# CMD: $cmd\"\n    echo \"# PWD: \"`pwd`\n    echo \"# ================================================================\"\n    $cmd\n    local st=$?\n    if (( $st )) ; then\n        echo \"EXIT: Command exited with status $st (FAILED).\"\n\techo \"      CMD: $cmd\"\n\texit 1\n    else\n        echo \"EXIT: Command exited with status $st (PASSED).\"\n    fi\n}\n\n# ================================================================\n# my-wget\n# ================================================================\nfunction my-wget() {\n    local src=\"$1\"\n    local dst=\"$2\"\n    if [ ! -f $dst ] ; then\n\tdocmd wget $src -O $dst\n    fi\n}\n\n# ================================================================\n# Setup\n# ================================================================\nmedir=$(dirname -- $(readlink -f $0))\nrootdir=$medir\nrtf=$rootdir\/rtf\narchive=$rootdir\/archives\nexport PATH=\"${rtf}\/bin:${PATH}\"\nrds=('pkgs' 'rtf' 'archives')\nfor rd in ${rds[@]} ; do\n    if [ ! -d $rd ] ; then\n\tdocmd mkdir $rd\n    fi\ndone\n\n# ================================================================\n# ant -- needed for rhino\n# ================================================================\nfn=apache-ant-1.8.4-bin.tar.bz2\narpath=$archive\/$fn \nmy-wget http:\/\/mirror.nexcess.net\/apache\/ant\/binaries\/$fn $arpath\n\nif [ ! -d pkgs\/apache-ant-1.8.4 ] ; then\n    pushd pkgs\n    docmd tar jxf $arpath\n    popd\nfi\n\n# Very simple install, just copy over the bin and lib dirs.\nif [ ! -f $rtf\/bin\/ant ] ; then\n    pushd pkgs\n    docmd rsync -avz apache-ant-1.8.4\/bin $rtf\/\n    docmd rsync -avz apache-ant-1.8.4\/lib $rtf\/\n    popd\nfi\ntest -f $rtf\/bin\/ant\n\n# ================================================================\n# node (npm) -- needed for jhint\n# ================================================================\nfn=node-v0.8.4.tar.gz\narpath=$archive\/$fn\nmy-wget http:\/\/nodejs.org\/dist\/v0.8.4\/$fn $arpath\n\nif [ ! -d pkgs\/node-v0.8.4 ] ; then\n    pushd pkgs\n    docmd tar zxf $arpath\n    popd\nfi\n\nif [ ! -f $rtf\/bin\/node ] ; then\n    pushd pkgs\/node-v0.8.4\n    docmd .\/configure --help\n    docmd .\/configure --prefix=$rtf\n    docmd make\n    docmd make install\n    popd\nfi\ntest -f $rtf\/bin\/node\n\n# ================================================================\n# jshint\n# ================================================================\nif [ ! -d pkgs\/node-jshint ] ; then\n    pushd pkgs\n    docmd env GIT_SSL_NO_VERIFY=true git clone https:\/\/github.com\/jshint\/node-jshint.git\n    popd\nfi\n\nif [ ! -f $rtf\/bin\/jshint ] ; then\n    pushd pkgs\/node-jshint\n    docmd .\/configure --prefix=$rtf\n    popd\nfi\ntest -f $rtf\/bin\/jshint\n\n# ================================================================\n# rhino -- javascript interpreter\n# ================================================================\nif [ ! -d pkgs\/rhino ] ; then\n    pushd pkgs\n    docmd env GIT_SSL_NO_VERIFY=true git clone https:\/\/github.com\/mozilla\/rhino.git\n    popd\nfi\n\nif [ ! -d rhino\/build ] ; then\n    pushd pkgs\/rhino\n    docmd ant\n    docmd ant compile-all\n    docmd ant jar\n    popd\nfi\n\nif [ ! -d $rtf\/rhino ] ; then\n    docmd rsync -avz pkgs\/rhino\/build $rtf\/rhino\/\nfi\n\nif [ ! -d $rtf\/bin\/rhino ] ; then\n    cat &gt;$rtf\/bin\/rhino &lt;&lt;EOF\n#!\/bin\/bash\n\n# This should handle spaces in arguments:\n#   rhino -e 'print(\"Hello, world!\")''\ni=0\nargv=()\nfor arg in \"\\$@\"; do\n    argv[\\$i]=\"\\$arg\"\n    i=\\$((i + 1))\ndone\n\n# Now execute the command.\njava -jar $rtf\/rhino\/build\/rhino1_7R5pre\/js.jar \"\\${argv[@]}\"\nEOF\n    chmod a+x $rtf\/bin\/rhino\nfi\ntest -f $rtf\/rhino\ntest -f $rtf\/bin\/rhino\n\n# ================================================================\n# Installation tests.\n# ================================================================\nif [ ! -f .OK ] ; then\n    docmd rhino -e 'print(\"hello\");'\n    cat &gt;$$.js &lt;&lt;EOF\nprint(\"hello, world\");\nEOF\n    docmd jshint $$.js\n    rm -f $$.js\n    touch .OK\nfi<\/code><\/pre>\n\nI hope that this is helpful.\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>I recently had to install jshint and rhino. It was a bit of a challenge because they needed ant and npm (node package manager). This blog describes what I did and provides a bash shell script that you can use.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[15,4,5,16],"tags":[28],"class_list":["post-783","post","type-post","status-publish","format-standard","hentry","category-bash","category-general","category-programming","category-sysadmin","tag-javascript"],"_links":{"self":[{"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/783","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=783"}],"version-history":[{"count":19,"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/783\/revisions"}],"predecessor-version":[{"id":1787,"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/783\/revisions\/1787"}],"wp:attachment":[{"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/joelinoff.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}