#+TITLE: JavaScript layer

[[file:img/javascript.png]] [[file:img/coffee.png]]

* Table of Contents                                         :TOC_4_gh:noexport:
 - [[#description][Description]]
   - [[#features][Features:]]
 - [[#install][Install]]
 - [[#configuration][Configuration]]
   - [[#tern][Tern]]
   - [[#indentation][Indentation]]
   - [[#repl][REPL]]
 - [[#key-bindings][Key Bindings]]
   - [[#js2-mode][js2-mode]]
   - [[#folding-js2-mode][Folding (js2-mode)]]
   - [[#refactoring-js2-refactor][Refactoring (js2-refactor)]]
   - [[#formatting-web-beautify][Formatting (web-beautify)]]
     - [[#documentation-js-doc][Documentation (js-doc)]]
   - [[#auto-complete-and-documentation-tern][Auto-complete and documentation (tern)]]
   - [[#json][JSON]]
   - [[#repl-skewer-mode][REPL (skewer-mode)]]

* Description

This layer adds support for the JavaScript language using [[https://github.com/mooz/js2-mode][js2-mode]].

** Features:
- Smart code folding
- Refactoring: done using [[https://github.com/magnars/js2-refactor.el][js2-refactor]].
- Auto-completion and documentation: provided by [[http://ternjs.net/][tern]]
- CoffeeScript support
- Formatting with [[https://github.com/yasuyk/web-beautify][web-beautify]]
- Get the path to a JSON value with [[https://github.com/Sterlingg/json-snatcher][json-snatcher]]
- REPL available via [[https://github.com/skeeto/skewer-mode][skewer-mode]] and [[https://github.com/pandeiro/livid-mode][livid-mode]]

* Install
To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =javascript= to the existing =dotspacemacs-configuration-layers= list in
this file.

You will also need to install =tern= to use the auto-completion and
documentation features:
#+BEGIN_SRC sh
  $ npm install -g tern
#+END_SRC

To use the formatting features, install =js-beautify=:
#+BEGIN_SRC sh
  $ npm install -g js-beautify
#+END_SRC

To activate error checking using flycheck, install one of the [[http://www.flycheck.org/en/latest/languages.html#javascript][available linters]]
such as =ESLint= or =JSHint=:
#+BEGIN_SRC sh
  $ npm install -g eslint
  # or
  $ npm install -g jshint
#+END_SRC

* Configuration
** Tern
To make tern re-use the server across multiple different editing sessions (thus
creating multiple =.tern-port= files for each document you have open [[http://ternjs.net/doc/manual.html][see here
for more details]]):

The variables provided below can be set when adding the =javascript=
configuration layer, as detailed in [[file:../../../doc/DOCUMENTATION.org::Setting%20configuration%20layers%20variables][this]] section of the documentation.

#+BEGIN_SRC emacs-lisp
  (javascript :variables javascript-disable-tern-port-files nil)
#+END_SRC

Windows users may need to set the variable =tern-command= in order for emacs to
locate and launch tern server successfully. See [[https://github.com/syl20bnr/spacemacs/issues/5733][this open issue for more
details]]. The variable can be set when adding the =javascript= configuration
layer:

#+BEGIN_SRC emacs-lisp
  (javascript :variables tern-command '("node" "/path/to/tern/bin/tern"))
#+END_SRC

** Indentation
To change how js2-mode indents code, set the variable =js2-basic-offset=, as
such:

#+BEGIN_SRC emacs-lisp
  (setq-default js2-basic-offset 2)
#+END_SRC

Similarly, to change how js-mode indents JSON files, set the variable
=js-indent-level=, as such:

#+BEGIN_SRC emacs-lisp
  (setq-default js-indent-level 2)
#+END_SRC

** REPL
To use the available JS repl, you need a running httpd server and a page loaded
with skewer. If a blank page serves your needs, just use the run-skewer command
in your javascript buffer. If you want to inject it in your own page, follow
[[https://github.com/skeeto/skewer-mode#skewering-with-cors][these instructions]] (install the Greasemonkey script and then click the triangle
in the top-right corner - if it turns green, you're good to go).

* Key Bindings

** js2-mode

| Key Binding | Description                          |
|-------------+--------------------------------------|
| ~SPC m w~   | toggle js2-mode warnings and errors  |
| ~%~         | jump between blockswith [[https://github.com/redguardtoo/evil-matchit][evil-matchit]] |

** Folding (js2-mode)

| Key Binding | Description              |
|-------------+--------------------------|
| ~SPC m z c~ | hide element             |
| ~SPC m z o~ | show element             |
| ~SPC m z r~ | show all element         |
| ~SPC m z e~ | toggle hide/show element |
| ~SPC m z F~ | toggle hide functions    |
| ~SPC m z C~ | toggle hide comments     |

** Refactoring (js2-refactor)

Bindings should match the plain emacs assignments.

| Key Binding   | Description                                                                                                    |
|---------------+----------------------------------------------------------------------------------------------------------------|
| ~SPC m k~     | deletes to the end of the line, but does not cross semantic boundaries                                         |
| ~SPC m r 3 i~ | converts ternary operator to if-statement                                                                      |
| ~SPC m r a g~ | creates a =/* global */= annotation if it is missing, and adds var to point to it                              |
| ~SPC m r a o~ | replaces arguments to a function call with an object literal of named arguments                                |
| ~SPC m r b a~ | moves the last child out of current function, if-statement, for-loop or while-loop                             |
| ~SPC m r c a~ | converts a multiline array to one line                                                                         |
| ~SPC m r c o~ | converts a multiline object literal to one line                                                                |
| ~SPC m r c u~ | converts a multiline function to one line (expecting semicolons as statement delimiters)                       |
| ~SPC m r e a~ | converts a one line array to multiline                                                                         |
| ~SPC m r e f~ | extracts the marked expressions into a new named function                                                      |
| ~SPC m r e m~ | extracts the marked expressions out into a new method in an object literal                                     |
| ~SPC m r e o~ | converts a one line object literal to multiline                                                                |
| ~SPC m r e u~ | converts a one line function to multiline (expecting semicolons as statement delimiters)                       |
| ~SPC m r e v~ | takes a marked expression and replaces it with a var                                                           |
| ~SPC m r i g~ | creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression |
| ~SPC m r i p~ | changes the marked expression to a parameter in a local function                                               |
| ~SPC m r i v~ | replaces all instances of a variable with its initial value                                                    |
| ~SPC m r l p~ | changes a parameter to a local var in a local function                                                         |
| ~SPC m r l t~ | adds a console.log statement for what is at point (or region)                                                  |
| ~SPC m r r v~ | renames the variable on point and all occurrences in its lexical scope                                         |
| ~SPC m r s l~ | moves the next statement into current function, if-statement, for-loop, while-loop                             |
| ~SPC m r s s~ | splits a =String=                                                                                              |
| ~SPC m r s v~ | splits a =var= with multiple vars declared into several =var= statements                                       |
| ~SPC m r t f~ | toggle between function declaration and function expression                                                    |
| ~SPC m r u w~ | replaces the parent statement with the selected region                                                         |
| ~SPC m r v t~ | changes local =var a= to be =this.a= instead                                                                   |
| ~SPC m r w i~ | wraps the entire buffer in an immediately invoked function expression                                          |
| ~SPC m r w l~ | wraps the region in a for-loop                                                                                 |
| ~SPC m x m j~ | move line down, while keeping commas correctly placed                                                          |
| ~SPC m x m k~ | move line up, while keeping commas correctly placed                                                            |

** Formatting (web-beautify)

| Key Binding | Description                                                  |
|-------------+--------------------------------------------------------------|
| ~SPC m =~   | beautify code in js2-mode, json-mode, web-mode, and css-mode |

*** Documentation (js-doc)

You can check more [[https://github.com/mooz/js-doc/][here]]

| Key Binding   | Description                           |
|---------------+---------------------------------------|
| ~SPC m r d b~ | insert JSDoc comment for current file |
| ~SPC m r d f~ | insert JSDoc comment for function     |
| ~SPC m r d t~ | insert tag to comment                 |
| ~SPC m r d h~ | show list of available jsdoc tags     |

** Auto-complete and documentation (tern)

| Key Binding   | Description                                                                              |
|---------------+------------------------------------------------------------------------------------------|
| ~SPC m C-g~   | brings you back to last place you were when you pressed M-..                             |
| ~SPC m g g~   | jump to the definition of the thing under the cursor                                     |
| ~SPC m g G~   | jump to definition for the given name                                                    |
| ~SPC m h d~   | find docs of the thing under the cursor. Press again to open the associated URL (if any) |
| ~SPC m h t~   | find the type of the thing under the cursor                                              |
| ~SPC m r r V~ | rename variable under the cursor using tern                                              |

** JSON

| Key Binding | Description                        |
|-------------+------------------------------------|
| ~SPC m h p~ | Get the path of the value at point |

** REPL (skewer-mode)

| Key Binding | Description                                                      |
|-------------+------------------------------------------------------------------|
| ~SPC m e e~ | evaluates the last expression                                    |
| ~SPC m e E~ | evaluates and inserts the result of the last expression at point |

| Key Binding | Description                                                                        |
|-------------+------------------------------------------------------------------------------------|
| ~SPC m s a~ | Toggle live evaluation of whole buffer in REPL on buffer changes                   |
| ~SPC m s b~ | send current buffer contents to the skewer REPL                                    |
| ~SPC m s B~ | send current buffer contents to the skewer REPL and switch to it in insert state   |
| ~SPC m s f~ | send current function at point to the skewer REPL                                  |
| ~SPC m s F~ | send current function at point to the skewer REPL and switch to it in insert state |
| ~SPC m s i~ | starts/switch to the skewer REPL                                                   |
| ~SPC m s r~ | send current region to the skewer REPL                                             |
| ~SPC m s R~ | send current region to the skewer REPL and switch to it in insert state            |
| ~SPC m s s~ | switch to REPL                                                                     |
