Function: js-jsx--syntax-propertize-tag
js-jsx--syntax-propertize-tag is a byte-compiled function defined in
js.el.gz.
Signature
(js-jsx--syntax-propertize-tag END)
Documentation
Determine if a JSXBoundaryElement is before END and propertize it.
Disambiguate JSX from inequality operators and arrow functions by testing for syntax only valid as JSX.
Source Code
;; Defined in /usr/src/emacs/lisp/progmodes/js.el.gz
(defun js-jsx--syntax-propertize-tag (end)
"Determine if a JSXBoundaryElement is before END and propertize it.
Disambiguate JSX from inequality operators and arrow functions by
testing for syntax only valid as JSX."
(let ((tag-beg (1- (point))) tag-end (type 'open)
name-beg name-match-data expr-attribute-beg unambiguous
forward-sexp-function) ; Use Lisp version.
(catch 'stop
(while (and (< (point) end)
(progn (skip-chars-forward " \t\n" end)
(< (point) end)))
(cond
((= (char-after) ?>)
;; Make the closing “>” a close parenthesis.
(put-text-property (point) (1+ (point)) 'syntax-table
(eval-when-compile (string-to-syntax ")<")))
(forward-char)
(setq unambiguous t)
(throw 'stop nil))
;; Handle a JSXSpreadChild (“<Foo {...bar}”) or a
;; JSXExpressionContainer as a JSXAttribute value
;; (“<Foo bar={…}”). Check this early in case continuing a
;; JSXAttribute parse.
((or (and name-beg (= (char-after) ?{))
(setq expr-attribute-beg nil))
(setq unambiguous t) ; JSXExpressionContainer post tag name ⇒ JSX
(when expr-attribute-beg
;; Remember that this JSXExpressionContainer is part of a
;; JSXAttribute, as that can affect its expression’s
;; indentation.
(put-text-property
(point) (1+ (point)) 'js-jsx-expr-attribute expr-attribute-beg)
(setq expr-attribute-beg nil))
(let (expr-end)
(condition-case nil
(save-excursion
(forward-sexp)
(setq expr-end (point)))
(scan-error nil))
(forward-char)
(if (>= (point) end) (throw 'stop nil))
(skip-chars-forward " \t\n" end)
(if (>= (point) end) (throw 'stop nil))
(if (= (char-after) ?}) (forward-char) ; Shortcut to bail.
;; Recursively propertize the JSXExpressionContainer’s
;; expression.
(js-syntax-propertize (point) (if expr-end (min (1- expr-end) end) end))
;; Exit the JSXExpressionContainer if that’s possible,
;; else move to the end of the propertized area.
(goto-char (if expr-end (min expr-end end) end)))))
((= (char-after) ?/)
;; Assume a tag is an open tag until a slash is found, then
;; figure out what type it actually is.
(if (eq type 'open) (setq type (if name-beg 'self-closing 'close)))
(forward-char))
((and (not name-beg) (looking-at js--dotted-name-re))
;; Don’t match code like “if (i < await foo)”
(if (js--unary-keyword-p (match-string 0)) (throw 'stop nil))
;; Save boundaries for later fontification after
;; unambiguously determining the code is JSX.
(setq name-beg (match-beginning 0)
name-match-data (match-data))
(goto-char (match-end 0)))
((and name-beg (looking-at js-jsx--attribute-name-re))
(setq unambiguous t) ; Non-unary name followed by 2nd name ⇒ JSX
;; Save JSXAttribute’s name’s match data for font-locking later.
(put-text-property (match-beginning 0) (1+ (match-beginning 0))
'js-jsx-attribute-name (match-data))
(goto-char (match-end 0))
(if (>= (point) end) (throw 'stop nil))
(skip-chars-forward " \t\n" end)
(if (>= (point) end) (throw 'stop nil))
;; “=” is optional for null-valued JSXAttributes.
(when (= (char-after) ?=)
(forward-char)
(if (>= (point) end) (throw 'stop nil))
(skip-chars-forward " \t\n" end)
(if (>= (point) end) (throw 'stop nil))
;; Skip over strings (if possible). Any
;; JSXExpressionContainer here will be parsed in the
;; next iteration of the loop.
(if (memq (char-after) '(?\" ?\' ?\`))
(progn
;; Record the string’s position so derived modes
;; applying syntactic fontification atypically
;; (e.g. js2-mode) can recognize it as part of JSX.
(put-text-property (point) (1+ (point)) 'js-jsx-string t)
(condition-case nil
(forward-sexp)
(scan-error (throw 'stop nil))))
;; Save JSXAttribute’s beginning in case we find a
;; JSXExpressionContainer as the JSXAttribute’s value which
;; we should associate with the JSXAttribute.
(setq expr-attribute-beg (match-beginning 0)))))
;; There is nothing more to check; this either isn’t JSX, or
;; the tag is incomplete.
(t (throw 'stop nil)))))
(when unambiguous
;; Save JSXBoundaryElement’s name’s match data for font-locking.
(if name-beg (put-text-property name-beg (1+ name-beg) 'js-jsx-tag-name name-match-data))
;; Make the opening “<” an open parenthesis.
(put-text-property tag-beg (1+ tag-beg) 'syntax-table
(eval-when-compile (string-to-syntax "(>")))
;; Prevent “out of range” errors when typing at the end of a buffer.
(setq tag-end (if (eobp) (1- (point)) (point)))
;; Mark beginning and end of tag for font-locking.
(put-text-property tag-beg (1+ tag-beg) 'js-jsx-tag-beg (cons type tag-end))
(put-text-property tag-end (1+ tag-end) 'js-jsx-tag-end tag-beg)
;; Use text properties to extend the syntax-propertize region
;; backward to the beginning of the JSXBoundaryElement in the
;; future. Typically the closing angle bracket could suggest
;; extending backward, but that would also involve more rigorous
;; parsing, and the closing angle bracket may not even exist yet
;; if the JSXBoundaryElement is still being typed.
(put-text-property tag-beg (1+ tag-end) 'syntax-multiline t))
(if (js-jsx--at-enclosing-tag-child-p) (js-jsx--syntax-propertize-tag-text end))))