--- /dev/null
+ About [![Build Status](https://travis-ci.org/mooz/js2-mode.png?branch=master)](https://travis-ci.org/mooz/js2-mode)
+ ======
+
+ Improved JavaScript editing mode for GNU Emacs ([description here](http://elpa.gnu.org/packages/js2-mode.html)).
+
+ For some of the latest changes, see [latest user-visible changes](https://github.com/mooz/js2-mode/wiki/Latest-user-visible-changes).
+
+ Installation
+ ======
+
+ The stable versions are hosted at [GNU ELPA](http://elpa.gnu.org/)
+ (<kbd>M-x list-packages</kbd>).
+
+ You can also install the latest development version from
+ [Melpa](http://melpa.milkbox.net/#installing).
+
+ Emacs 22 and 23
+ ===============
+
+ This version requires Emacs 24. For a backward compatible version,
+ check out the branch
+ [emacs23](https://github.com/mooz/js2-mode/tree/emacs23).
+
+ Bugs
+ ====
+
+ If you find problems, please report them at <http://github.com/mooz/js2-mode/issues>.
+
+ See Also
+ ======
+
+ Some third-party modes that use the generated syntax tree:
+
+ * [js2-refactor](https://github.com/magnars/js2-refactor.el)
+ * [skewer-mode](https://github.com/skeeto/skewer-mode)
--- /dev/null
+ (require 'ert)
+ (require 'js2-mode)
+
+ (defun js2-test-indent (content)
+ (let ((s (replace-regexp-in-string "^ *|" "" content)))
+ (with-temp-buffer
+ (insert (replace-regexp-in-string "^ *" "" s))
+ (js2-mode)
+ (indent-region (point-min) (point-max))
+ (should (string= s (buffer-substring-no-properties
+ (point-min) (point)))))))
+
+ (defmacro* js2-deftest-indent (name content &key bind)
+ `(ert-deftest ,(intern (format "js2-%s" name)) ()
+ (let ,(append '((js2-basic-offset 2)
+ (js2-pretty-multiline-declarations t)
+ (inhibit-point-motion-hooks t))
+ bind)
+ (js2-test-indent ,content))))
+
+ (put 'js2-deftest-indent 'lisp-indent-function 'defun)
+
+ (js2-deftest-indent no-multiline-decl-indent-after-semicolon
+ "var foo = 1;
+ |bar = 2")
+
+ (js2-deftest-indent multiline-decl-indent-after-comma
+ "let foo = 1,
+ | bar = 2")
+
+ (js2-deftest-indent no-multiline-decl-when-disabled
+ "let foo = 1,
+ |bar = 2"
+ :bind ((js2-pretty-multiline-declarations nil)))
+
+ (js2-deftest-indent multiline-decl-with-continued-expr
+ "var foo = 100500
+ | + 1")
+
+ (js2-deftest-indent multiline-decl-with-continued-expr-same-line
+ "var foo = 100500 /
+ | 16;")
+
+ (js2-deftest-indent no-multiline-decl-with-operator-inside-string
+ "var foo = bar('/protocols/')
+ |baz()")
+
+ (js2-deftest-indent no-multiline-decl-implicit-semicolon
+ "var foo = 100500
+ |1")
+
+ (js2-deftest-indent multiline-decl-sees-keyword-width
+ "const foo = 1,
+ | bar = 2;")
+
+ (js2-deftest-indent multiline-decl-second-arg-value-parenthesised
+ "var foo = 1,
+ | bar = [
+ | 1, 2,
+ | 3, 4
+ | ],
+ | baz = 5;")
+
+ (js2-deftest-indent multiline-decl-first-arg-function-normal
+ "var foo = function() {
+ | return 7;
+ |},
+ | bar = 8;")
+
+ (js2-deftest-indent multiline-decl-first-arg-function-indent-all
+ "var foo = function() {
+ | return 7;
+ | },
+ | bar = 8;"
+ :bind ((js2-pretty-multiline-declarations 'all)))
--- /dev/null
+ (require 'ert)\r
+ (require 'ert-x)\r
+ (require 'js2-mode)\r
+ \r
+ (defun js2-test-string-to-ast (s)\r
+ (ert-with-test-buffer (:name 'origin)\r
+ (insert s)\r
+ (js2-mode)\r
+ (should (null js2-mode-buffer-dirty-p))\r
+ js2-mode-ast))\r
+ \r
+ (defun js2-test-parse-string (code-string &key syntax-error)\r
+ (let ((ast (js2-test-string-to-ast code-string)))\r
+ (if syntax-error\r
+ (let ((errors (js2-ast-root-errors ast)))\r
+ (should (= 1 (length errors)))\r
+ (destructuring-bind (_ pos len) (first errors)\r
+ (should (string= syntax-error (substring code-string\r
+ (1- pos) (+ pos len -1))))))\r
+ (should (= 0 (length (js2-ast-root-errors ast))))\r
+ (ert-with-test-buffer (:name 'copy)\r
+ (js2-print-tree ast)\r
+ (skip-chars-backward " \t\n")\r
+ (should (string= code-string (buffer-substring-no-properties\r
+ (point-min) (point))))))))\r
+ \r
+ (defmacro* js2-deftest-parse (name code-string &key bind syntax-error)\r
+ "Parse CODE-STRING. If SYNTAX-ERROR is nil, print syntax tree\r
+ with `js2-print-tree' and assert the result to be equal to the\r
+ original string. If SYNTAX-ERROR is passed, expect syntax error\r
+ highlighting substring equal to SYNTAX-ERROR value.\r
+ BIND defines bindings to apply them around the test."\r
+ `(ert-deftest ,(intern (format "js2-%s" name)) ()\r
+ (let ,(append bind '((js2-basic-offset 2)))\r
+ (js2-test-parse-string ,code-string :syntax-error ,syntax-error))))\r
+ \r
+ (put 'js2-deftest-parse 'lisp-indent-function 'defun)\r
+ \r
+ ;;; Callers of `js2-valid-prop-name-token'.\r
+ \r
+ (js2-deftest-parse parse-property-access-when-not-keyword\r
+ "A.foo = 3;")\r
+ \r
+ (js2-deftest-parse parse-property-access-when-keyword\r
+ "A.in = 3;"\r
+ :bind ((js2-allow-keywords-as-property-names t)))\r
+ \r
+ (js2-deftest-parse parse-property-access-when-keyword-no-xml\r
+ "A.in = 3;"\r
+ :bind ((js2-allow-keywords-as-property-names t)\r
+ (js2-compiler-xml-available nil)))\r
+ \r
+ (js2-deftest-parse parse-array-literal-when-not-keyword\r
+ "a = {b: 1};")\r
+ \r
+ (js2-deftest-parse parse-array-literal-when-keyword\r
+ "a = {in: 1};"\r
+ :bind ((js2-allow-keywords-as-property-names t)))\r
+ \r
+ ;;; 'of' contextual keyword.\r
+ \r
+ (js2-deftest-parse parse-array-comp-loop-with-of\r
+ "[a for (a of [])];")\r
+ \r
+ (js2-deftest-parse parse-for-of\r
+ "for (var a of []) {\n}")\r
+ \r
+ (js2-deftest-parse of-can-be-var-name\r
+ "var of = 3;")\r
+ \r
+ (js2-deftest-parse of-can-be-function-name\r
+ "function of() {\n}")\r
+ \r
+ ;;; Destructuring binding.\r
+ \r
+ (js2-deftest-parse destruct-in-declaration\r
+ "var {a, b} = {a: 1, b: 2};")\r
+ \r
+ (js2-deftest-parse destruct-in-arguments\r
+ "function f({a: aa, b: bb}) {\n}")\r
+ \r
+ (js2-deftest-parse destruct-in-array-comp-loop\r
+ "[a + b for ([a, b] in [[0, 1], [1, 2]])];")\r
+ \r
+ (js2-deftest-parse destruct-in-catch-clause\r
+ "try {\n} catch ({a, b}) {\n a + b;\n}")\r
+ \r
+ ;;; Function parameters.\r
+ \r
+ (js2-deftest-parse function-with-default-parameters\r
+ "function foo(a = 1, b = a + 1) {\n}")\r
+ \r
+ (js2-deftest-parse function-with-no-default-after-default\r
+ "function foo(a = 1, b) {\n}"\r
+ :syntax-error "b")\r
+ \r
+ (js2-deftest-parse function-with-destruct-after-default\r
+ "function foo(a = 1, {b, c}) {\n}"\r
+ :syntax-error "{")\r
+ \r
+ (js2-deftest-parse function-with-rest-parameter\r
+ "function foo(a, b, ...rest) {\n}")\r
+ \r
+ (js2-deftest-parse function-with-param-after-rest-parameter\r
+ "function foo(a, ...b, rest) {\n}"\r
+ :syntax-error "rest")\r
+ \r
+ (js2-deftest-parse function-with-destruct-after-rest-parameter\r
+ "function foo(a, ...b, {}) {\n}"\r
+ :syntax-error "{}")\r
+ \r
+ (js2-deftest-parse function-with-rest-after-default-parameter\r
+ "function foo(a = 1, ...rest) {\n}")\r