Code Monkey home page Code Monkey logo

rjsx-mode's Introduction

rjsx-mode: A major mode for editing JSX files

MELPA MELPA Stable Build Status

This mode derives from js2-mode, extending its parser to support JSX syntax according to the official spec. This means you get all of the js2 features plus proper syntax checking and highlighting of JSX code blocks.

Here's a screenshot of it in action:

Actual syntax highlighting and no spurious errors!

Installing

rjsx-mode is available on Melpa, so if you have that repository configured you can just package-list-packages and install it from there. (If not, you can follow their guide on getting started). rjsx-mode automatically registers itself for *.jsx files, but you can use (add-to-list 'auto-mode-alist '("components\\/.*\\.js\\'" . rjsx-mode))

Alternatively, you can download rjsx-mode.el from this repository and use load-file or similar to add it to your current session.

Features

js2-mode does not include a JSX parser, but rather an E4X parser, which means it gets confused with certain JSX constructs. This mode extends the `js2** parser to support all JSX constructs and proper syntax highlighting and indentation.

rjsx-mode adds some electricity to < and C-d to make adding new JSX elements less repetitive:

  • < inserts </> whenever it would start a new JSX node (and simply inserts < otherwise)
  • > or C-d right before the slash in a self-closing tag automatically inserts a closing tag and places point inside the element

The result is you can do the following:

Quickly and easily add new components

  • C-c C-r lets you rename the enclosing tag

Some features that this mode adds to js2:

  • Proper indentation of JSX regardless of how you write it. (No need to wrap in parentheses!)
  • Highlighting JSX tag names and attributes (using the rjsx-tag and rjsx-attr faces)
  • Parsing the spread operator {...otherProps}
  • && and || in child expressions <div>{cond && <BigComponent/>}</div>
  • Ternary expressions <div>{toggle ? <ToggleOn /> : <ToggleOff />}</div>

If you don't like this behavior, you can disable it by adding the following to your init file:

(with-eval-after-load 'rjsx-mode
  (define-key rjsx-mode-map "<" nil)
  (define-key rjsx-mode-map (kbd "C-d") nil)
  (define-key rjsx-mode-map ">" nil))

Additionally, since rjsx-mode extends the js2 AST, utilities using the parse tree gain access to the JSX structure.

Indentation

rjsx-mode extends the built-in javascript indentation engine to correctly support JSX. You can configue the depth of indentation using js-indent-level and sgml-basic-offset, along with the various js-indent- variables.

Indenting with tabs: This is not currently supported. You can either submit a PR if interested (look at issue #85) or revert to using the built-in indentation mode by adding (setq-local indent-line-function 'js-jsx-indent-line) to your rjsx-mode-hook.

Bugs, contributing

Please submit any bugs or feature requests on the GitHub tracker. Since this mode is based on js2, it is possible that bugs you encounter with it stem from there. Please try reproducing bugs using js2-mode if relevant. If the bug is in js2, please report it using M-x report-emacs-bug.

License

This project is licensed under the MIT license.

rjsx-mode's People

Contributors

axyz avatar bzalasky avatar felipeochoa avatar jcs090218 avatar larebsyed avatar liuchong avatar nikolas avatar syohex avatar wasamasa avatar wyuenho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

rjsx-mode's Issues

rjsx-delete-creates-full-tag errors with "rjsx-node does not define visitor-traversal function"

My C-d has stopped working recently. Has something in rjsx-mode changed or should I be looking into my own config? Thanks!

To repro:

  1. Open a new scratch buffer

  2. M-x rjsx-mode

  3. Type:

    const foo = <div
  4. That should insert the />, press C-d

Debugger entered--Lisp error: (error "rjsx-node does not define a visitor-traversal function")
  signal(error ("rjsx-node does not define a visitor-traversal function"))
  error("%s does not define a visitor-traversal function" rjsx-node)
  js2-visit-ast(#s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#4) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #2 :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #3) :kids (#2) :decl-type 153) :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #2 :name "foo" :scope nil) :initializer #1) :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #1 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil) js2-node-at-point-visitor)
  js2-visit-var-init-node(#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#3) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #1 :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #2) :kids (#1) :decl-type 153) :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #1 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #1 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #2 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) js2-node-at-point-visitor)
  js2-visit-ast(#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#3) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #1 :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #2) :kids (#1) :decl-type 153) :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #1 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #1 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #2 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) js2-node-at-point-visitor)
  js2-visit-var-decl(#s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#2) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #1 :target #7 :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #8 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #9 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #1) :kids (#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #1 :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #3 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #3 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #4 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil))) :decl-type 153) js2-node-at-point-visitor)
  js2-visit-ast(#s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#2) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #1 :target #7 :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #8 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #9 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #1) :kids (#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #1 :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #3 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #3 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #4 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil))) :decl-type 153) js2-node-at-point-visitor)
  js2-visit-expr-stmt-node(#s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#1) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #1 :kids (#7) :decl-type 153) :target #6 :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #7 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #8 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #1 :kids (#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #2 :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #4 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #4 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #5 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil))) :decl-type 153)) js2-node-at-point-visitor)
  js2-visit-ast(#s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#1) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #1 :kids (#7) :decl-type 153) :target #6 :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #7 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #8 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) :expr #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #1 :kids (#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #2 :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #4 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #4 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #5 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil))) :decl-type 153)) js2-node-at-point-visitor)
  js2-visit-ast-root(#s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #1 :expr #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #3 :kids (#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #4 :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #6 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #6 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #7 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil))) :decl-type 153))) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #1 :expr #7) :kids (#6) :decl-type 153) :target #5 :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #6 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #7 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) js2-node-at-point-visitor)
  js2-visit-ast(#s(js2-ast-root :type 135 :pos 1 :len 18 :props nil :parent nil :kids (#s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #1 :expr #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #3 :kids (#s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #4 :target #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #6 :name "foo" :scope nil) :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #6 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #7 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil))) :decl-type 153))) :symbol-table ((foo . #s(js2-symbol :decl-type 153 :name "foo" :ast-node #s(js2-name-node :type 39 :pos 0 :len 3 :props nil :parent #s(js2-var-init-node :type 153 :pos 6 :len 12 :props nil :parent #s(js2-var-decl-node :type 121 :pos 0 :len 18 :props nil :parent #s(js2-expr-stmt-node :type 132 :pos 0 :len 18 :props nil :parent #1 :expr #7) :kids (#6) :decl-type 153) :target #5 :initializer #s(rjsx-node :type 58 :pos 6 :len 6 :props nil :parent #6 :name #s(rjsx-member :type 61 :pos 1 :len 3 :props nil :parent #7 :dots-pos nil :idents (#s(rjsx-identifier :type 60 :pos 14 :len 3 :props nil :parent nil :namespace nil :name #s(js2-name-node :type 39 :pos 14 :len 3 :props nil :parent nil :name "div" :scope nil)))) :rjsx-props nil :kids nil :closing-tag nil)) :name "foo" :scope nil)))) :parent-scope nil :top nil :functions nil :regexps nil :symbols nil :param-count 0 :var-names nil :consts nil :temp-number 0 :buffer "*scratch*" :comments nil :errors nil :warnings nil :node-count nil) js2-node-at-point-visitor)
  js2-node-at-point(17 t)
  rjsx--tag-at-point()
  rjsx-delete-creates-full-tag(1)
  funcall-interactively(rjsx-delete-creates-full-tag 1)
  call-interactively(rjsx-delete-creates-full-tag nil nil)
  command-execute(rjsx-delete-creates-full-tag)

JSX tags not working with js2-highlight-vars

For some reason js2-highlight-vars does not pick up on the JSX tag names. E.g.,

import Component from 'abc';

const c = () => (
    <Component/>
);

With point at the second Component, js2-highlight-vars does not highlight anything. Calling js2-node-at-point returns an rjsx-member rather than a js2-name node

File mode specification error: (void-function js2--struct-put)

To fix this error, update js2-mode.

This is not a issue, just a report.

Today I installed rjs-mode, then got the following error in rjsx-mode:

File mode specification error: (void-function js2--struct-put)

This is due to calling js2-mode's new function js2--struct-put.
And I already installed js2-mode some months ago.
(My installed js2-mode didn't have js2--struct-put yet)

js2-mode added js2--struct-put function at:

commit 97d27d664aed3aaf4332358fd805f64694c53436
Date:   Thu May 4 04:46:38 2017 +0300

rjsx-mode added js2--struct-put call at:

commit 1a7f75b2b6674899aa70fc7961969df6098abfb9
Date:   Mon Jul 10 16:06:37 2017 +0200

Both are new.
So better to add dependency notice in README.md?
(like "Update js2-mode before install rjsx-mode")

Thank you for developing rjsx-mode!

Add support for flowtype

Hi,

I use rjsx-mode for my projects. I am learning React-Native, I write flow/jsx flow
but the sintax is not not recognized, please look emacs-flow-jsx, I can combine the two solutions?

Thank you so much

Stable releases should have stable dependencies

The version of rjsx-mode deployed on MELPA stable depends on js2-mode 20170504 which is not available yet (currently only js2-mode 20170116 is available as a stable release).

As a result of the above combination, I cannot install rjsx-mode unless I enable the unstable MELPA repository, which makes the stable release of rjsx-mode not that useful.

Is it possible to downgrade the dependency on js2-mode to the stable one?

Silence warning about missing optional semicolon

Is it possible to turn off warnings about the missing optional semicolons?

Turning it off for all semicolons, not just optional ones would be an acceptable approximation, as far as I'm concerned.

Better recovery from malformed attribute expressions

There are three possibilities for recovering from a missing RC:

  1. Do nothing This works best for attributes in the middle when they have a value (e.g., a={123 b="...") since the js2 expression parser won't consume extra tokens, letting additional attributes be tokenized properly. In contrast, when the attribute is the last one in the tag the parser will happily give us a greater-than expression using the closing GT from the tag, messing everything up. There's not much we can do to distinguish between correct and incorrect parsing there. In self-closing tags js2 would parse the / as division, then > as an error primary expression, and then who knows.

  2. Un-parse the expression This works best for attributes where there's not even a value If we're a middle attribute, js2 will try to parse the next attribute as an assignment of an object literal or string. It can be a valid assignment (a={ b={abc}, a={ b="str"), an error due to a spread op (a={ {...abc}), or an error due to an invalid object literal body (a={ b={a > b}. When the assignment is valid, js2 may keep going if we're at the end of the tag, using the / or > to form expressions.

    If we're at the end of a tag, js2 will parse either a regex (for self-closing tags) or anything goes for an expression starting with > (which is de facto treated as its own primary expression).

  3. Consume up to the next RC. This fixes malformed/partially formed expressions inside the curlies. E.g., a={pred ? b}

Allow props to take a JSX literal value

Also per the spec on the repo, apparently props can be assigned literal JSX elements directly

JSXAttributeInitializer :


  • = JSXAttributeValue

JSXAttributeValue :


  • " JSXDoubleStringCharactersopt "
  • ' JSXSingleStringCharactersopt '
  • { AssignmentExpression }
  • JSXElement

JSX not formatted correctly

Other editors like WebStorm and VSCode seem to format/understand a fat arrow expression, followed by linebreak, followed by a JSX tag, but rjsx-mode seems to trip on this.
IE:

const Bar = () =>
  <div>
    //add a new tag here/hit enter and it is put at the same indentation as div
  </div>

Thanks for your excellent work on this mode! I've definitely seen an improvement over the react layer already.

indentation of component attributes

Current behavior:

<MyComp attr1=v1
        attr2=v2
        attr3=v3 />

I expect:

<MyComp attr1=v1
    attr2=v2
    attr3=v3 />

The reason is simple, in refactoring, we may use different component name but same attributes. The second style produces smaller diff.

I'm fine to keep the current indentation style by default. But it would be great if there were some flag to switch to second style.

How does rjsx-mode play with js2-mode and can it take options

Hi @felipeochoa,
thank you for this great library, it works great!
I have one problem: I am not sure if I have to also include and configure js2-mode or js2-jsx-mode? Should I do anything with these two or is having just rjsx-mode enough? Also, how can I specify options to rjsx-mode, like indentation level and similar?

Thanks!

Less than conditionals in curly braces seem to trip up the indenter

I was seeing some wonky indentation, and I did a little sleuthing. I found that the presence of a < inside curly braces seems to cause closing tags to be misplaced. Here's an example:

import React, { Component } from 'react';

const a = 1, b = 2;

// Okay
const ExampleWithEquals = (props) => {
  return (
    <div>
      { a === b ? <span>This indentation is just dandy.</span> : null }
    </div>
  );
};

// Okay
const ExampleWithGreaterThan = (props) => {
  return (
    <div>
      { a >  b ? <span>This indentation okay, also.</span> : null }
    </div>
  );
};

// Not Okay
const ExampleWithLessThan = (props) => {
  return (
    <div>
      { a <  b ? <span>This indentation is not so nice.</span> : null }
             </div>
  );
};

Command to wrap region in an element

It would be nice to have a structure-aware command to wrap the region with a new JSX element, similar to web-mode-element-wrap, but preserving a valid JSX file.

C-d not available in evil mode

By default "c-d" is not available in evil-mode as it's bound to another shortcut and so rjsx-delete-creates-full-tag is not available. I rebound it to ">" instead and this seems to work quite well. Perhaps this could work as an alternative to the "c-d" shortcut?

Use different syntax table for JSX text

We should use put-text-property to set a different syntax table on stretches of JSX text. Not sure which syntax table is best, it should be more text-like. One issue in particular is single quotes messing up the syntax parser when they're unmatched (e.g., in a contraction). Probably should use an SGML syntax table, but maybe just fundamental itself?

Workaround to enable flycheck eslint checker

Locate this line (flycheck-define-checker javascript-eslint in flycheck.el(usually in ~/.emacs.d/elpa/flycheck-30/),

  1. in the flycheck-define-checker call, change:
    :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode) to:
    :modes (js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode rjsx-mode)
  2. byte-recompile-file flycheck.el
  3. reload flycheck.el

JSX string parsing

We're currently using js2-mode's string node to parse string properties in JSX, but the syntax is slightly different. Whereas Javascript (and hence js2) allows one to escape quotes: "He said, \"Don't you worry child\"", JSX does not. So the js2 parser is slightly more tolerant than the spec

Have to force quit emacs when typing <

Hi,

I'm on macOS, using GNU Emacs 25.2.1 (x86_64-apple-darwin13.4.0, NS appkit-1265.21 Version 10.9.5 (Build 13F1911)) of 2017-04-21 and loading rjsx-mode like this:
(req-package rjsx-mode :config (add-to-list 'auto-mode-alist '("\\.jsx?$" . rjsx-mode)))
When I enter a render function and type "<" emacs freezes and I have to force quit.
For now I'm fixing it like this:
(req-package rjsx-mode :config (add-to-list 'auto-mode-alist '("\\.jsx?$" . rjsx-mode)) (with-eval-after-load 'rjsx-mode (define-key rjsx-mode-map "<" nil) (define-key rjsx-mode-map (kbd "C-d") nil)))
However, I'd like to use the "<" feature. So I'm looking forward to a fix ;-) Let me know if I can provide additional debugging information.

can't type closing curly bracket (in combination with autopair-mode)

Sorry to report another bug that only seems to surface in a certain configuration. Here's how it can be reproduced:

(load-file "~/.emacs.d/elpa/js2-mode-20171014.1229/js2-mode.el")
(load-file "~/.emacs.d/elpa/rjsx-mode-20171025.1621/rjsx-mode.el")
(load-file "~/.emacs.d/elpa/autopair-20160304.437/autopair.el")

Open a file with this content (in rjsx-mode with autpair-mode enabled)

class ShoppingList extends Component {
  render() {
    return (
      <div className="shopping-list">
	<h1>Shopping list for {this.props.name </h1></div>
  }
}

(note: I am aware of the missing ), but this bug basically forces a certain order in which to fix the parentheses.)
Attempt to type the closing curly bracket and get the error:

js2-mode-forward-sexp: Args out of range: #<buffer App.jsx>, 158, 688 [4 times]

Issue only occurs with rjsx-mode. js2-jsx-mode does not show the same problem.

Custom indent levels for closing tags

Hi there, the JSX project that I work on has a strict style guide which states that if a tag has more than one attribute then the attributes should each be on a new line, e.g.

<div 
  id="Foo"
  className="foo"
>
  <List className="foo__list">
    { props.items.map(item => <label className="foo__label">{item.text}</label>) }
  </List>
  <Footer
    className="foo__footer"
    text={props.footer}
  />
</div>

And in order to de-mark child elements more easily, the style guide also says that the closing angled bracket of a tag should be on a new line and indented inline with the opening tag. RJSX-Mode indents the closing tags inline with the props, e.g.

<div 
  id="Foo"
  className="foo"
  >

I know this might not be a usual case, but I was wondering if it is (or could be) possible to configure the indent level of closing tags on new lines?

Incorrect handling of string context

export default () => (
    <div>
      You've created a user
    </div>
)

If you put the cursor before You and call (syntax-ppss) you will get nil for the string context, whereas placing the cursor at created and calling (syntax-ppss) will give you 39 (ascii for '). This breaks some tools relying on the string/commend status as reported by emacs. It would be cool if we could mark all the quotes in "text nodes" in the tree with text properties disabling the pairing of quotes.

See https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-Properties.html#Syntax-Properties

Edit: You can even see the "error" in how github renders the snippet. Quite convenient in regard to this report :D

Indention bugs are related to unstable dependency

Hi Felipe,

Thank you for creating this module, I hope more people will use it and it'll become default in popular distros like spacemacs.

Currently there is a little problem with it; it depends on an unstable version of js2-mode. It's not your fault, probably js2-mode needs to update their package in stable streams. Their latest update on Stable Melpa and GNU packages is version 20170116, but rjsx-mode depends on a newer version, which could be considered as newer version.

This problem causes indentation issues for people using stable registries. The tab button was not working me until I installed the unstable version of js2-mode. May be you can note this detail in your README to guide new users.

Thanks for the great work,
Azer

More intelligently try to match tags

When a child JSX tag is missing a closing tag, the current code uses its parent tag as a mismatched tag, so its parent ends up missing a tag and the rest of the buffer is screwed. By deferring matching of opening and closing tags to rjsx-parse-xml we could be smarter about this matching process.

image

Evil mode

Deleting the slash in a self-closing tag does not insert a closing tag when using evil mode.

rjsx-delete-creates-full-tag sometimes doesn't work

I noticed that sometimes pressing C-d wouldn't work, it would just delete the next character. I eventually realized that this happened when the tag name hadn't been highlighted yet so at first I added an advice to (font-lock-ensure) :before the function but that didn't work and I remembered that js2-mode's whole point was about parsing the buffer in order to provide better highlighting, so I changed that call to (js2-reparse) and everything seems to be working now!

(define-advice rjsx-delete-creates-full-tag
    (:before (n &optional killflag) js2-reparse)
  "Ensure the document is parsed before attempting to proceed."
  (js2-reparse))

I'm no expert in js2-mode's internals though, and perhaps there's a better approach to this than reparsing the entire buffer, but at least for my uses it doesn't seem to be much of an issue so far.

Closing bracket not align according to eslint (jsx-closing-bracket-location)

Hi,
I'm using AirBnB styleguide, and I have problems meeting jsx-closing-bracket-location rule.

Ideally I want my closing tag to be formatted like so:

<Hello
  firstName="John"
  lastName="Smith"
/>;

However I end up with:

<Hello
  firstName="John"
  lastName="Smith"
  />;

Maybe someone had this issue and knows a workaround/patch?

Fails to load after Flycheck is loaded

Since 86549c1 rjsx-mode fails to load after Flycheck is loaded (irrelevant parts elided):

Debugger entered--Lisp error: (void-function \(setf\ flycheck-checker-get\))
  \(setf\ flycheck-checker-get\)((rjsx-mode js-mode js-jsx-mode js2-mode js2-jsx-mode js3-mode) javascript-eslint modes)
  …

The cause is a miscompiled push form introduced in 86549c1. In a clean session—which package.el uses when compiling asynchronously—Flycheck isn't loaded when the body of with-eval-after-load is compiled flycheck isn't loaded, so push doesn't have the GV setter definition for flycheck-checker-get in scope and thus doesn't expand to a proper setf call.

Speaking as Flycheck's maintainer I'd also like to point out that it's not how we prefer Flycheck's API to be used in 3rd party packages.

Why not open a pull request for Flycheck to directly add rjsx-mode to our syntax checker definitions?

minor html inssues

  1. indentation
<div
  prop1="3"
  />

I think the the last /> should not indent two spaces according to the popular coding style

  1. I'd rather rjsx not fill the slash character when I insert a new component directive. Many of our components use this.props.children (typical in enterprise applications), the auto inserted / is real annoying.

Update license to GPL

This project uses significant parts of the js2-mode package. The js2-mode package is licensed under the GPLv3 by the Free Software Foundation.

According to the license terms, this project is de jure subject to the GPLv3 license. Saying otherwise would be misleading. See: If a library is released under the GPL (not the LGPL), does that mean that any software which uses it has to be under the GPL or a GPL-compatible license?

Please update the license to clear confusion that may arise.

Support for Key Combo

Hi there, thank you very much for this package! It's by far the most comprehensive JSX mode..

However, I use Key Combo and when entering an = character it replaces it by = which I don't wanna do inside JSX tags, i.e.

var x=
// becomes
var x = 

I used to use web-mode and with that, I added some advice to the key-combo-pre-command-function which would ignore this combo inside JSX, with

(advice-add
   'key-combo-pre-command-function
   :around '(lambda (orig-f &rest args)
              (unless  (and (or (web-mode-jsx-is-html)
                                (equal web-mode-content-type "html"))
                            (member (this-command-keys) '("=" "-" "+")))
                (apply orig-f args))))

So you can see the function (web-mode-jsx-is-html) would tell me I'm inside a JSX tag.

I was just wondering how I would do this using the JS2 parser and RJSX? Any help would be appreciated! Thanks

Allow props without an initializer

In the spec on the github repo, attributes are allowed to not specify a value:

JSXAttribute :


  • JSXAttributeName JSXAttributeInitializeropt

JSXAttributeName :

  • JSXIdentifier
  • JSXNamespacedName

JSXAttributeInitializer :


  • = JSXAttributeValue

Allow kebab-case identifiers

Per the spec, one valid production for identifiers is JSXIdentifier NO WHITESPACE OR COMMENT -. Not sure how we'll enforce the no whitespace or comment bit, but should at least be able to support kebab-cased identifiers.

capture

Make '>' electric

It would be great if typing > at the end of a component automatically inserted the matching end tag

bad function rjsx-electric-lt

If I press < in rjsx-mode emacs stop responding to any keypresses and eat my RAM (I kill it with SIGKILL after 4,1 GB). Maybe it's infinite loop.

Identation

Hello, guys!
First of all thank you for making this mode.
Second of all, I have a small issue, and maybe I can get some help.
I am using a react-based javascript framework, and I would like to ask for a small feature.
screen shot 2017-01-14 at 19 53 03

In line number 4 the curly bracket is not aligned properly (I think the reason is that I have 2 html tags
separated by comma). But still, can you help me figure out how to fix this? I noticed how the identation is made properly in other modes, but I really like the behaviour of this mode and I am not willing to give up to it because of this small bug.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.