magnars-js2r-extract-function.md
(defun js2r--extract-fn (name goto-position call-template function-template)
(js2r--guard)
(js2r--wait-for-parse
(unless (use-region-p)
(error "Mark the expressions to extract first"))
(save-excursion
(let* ((parent (js2r--first-common-ancestor-in-region (region-beginning) (region-end)))
(block (js2r--closest-node-where #'js2-block-node-p parent))
(fn (js2r--closest-node-where #'js2-function-node-p block))
(exprs (js2r--marked-expressions-in-block block))
(vars (-mapcat #'js2r--name-node-decendants exprs))
(local (--filter (js2r--local-to-fn-p fn it) vars))
(names (-distinct (-map 'js2-name-node-name local)))
(declared-in-exprs (-map #'js2r--var-init-node-target-name (-mapcat #'js2r--var-init-node-decendants exprs)))
(outside-exprs (-difference (js2-block-node-kids block) exprs))
(outside-var-uses (-map #'js2-name-node-name (-mapcat #'js2r--name-node-decendants outside-exprs)))
(declared-in-but-used-outside (-intersection declared-in-exprs outside-var-uses))
(export-var (car declared-in-but-used-outside))
(params (-difference names declared-in-exprs))
(params-string (mapconcat #'identity (reverse params) ", "))
(first (car exprs))
(last (car (last exprs)))
(beg (js2-node-abs-pos (car exprs)))
(end (js2-node-abs-end last))
(contents (buffer-substring beg end)))
(goto-char beg)
(delete-region beg end)
(when (js2-return-node-p last)
(insert "return "))
(when export-var
(setq contents (concat contents "\nreturn " export-var ";"))
(insert "var " export-var " = "))
(insert (format call-template name params-string))
(goto-char (js2-node-abs-pos fn))
(when goto-position (funcall goto-position))
(let ((start (point)))
(insert (format function-template name params-string contents))
(indent-region start (1+ (point))))))))
(defun js2r-extract-function (name)
"Extract a function from the closest statement expression from the point."
(interactive "sName of new function: ")
(js2r--extract-fn
name
(lambda ()
(unless (js2r--looking-at-function-declaration)
(goto-char (js2-node-abs-pos (js2r--closest #'js2-expr-stmt-node-p)))))
"%s(%s);"
"function %s(%s) {\n%s\n}\n\n"))
Language:Clojure
(defun js2r--extract-fn (name goto-position call-template function-template)
(js2r--guard)
(js2r--wait-for-parse
(unless (use-region-p)
(error "Mark the expressions to extract first"))
(save-excursion
(let* ((parent (js2r--first-common-ancestor-in-region (region-beginning) (region-end)))
(block (js2r--closest-node-where #'js2-block-node-p parent))
(fn (js2r--closest-node-where #'js2-function-node-p block))
(exprs (js2r--marked-expressions-in-block block))
(vars (-mapcat #'js2r--name-node-decendants exprs))
(local (--filter (js2r--local-to-fn-p fn it) vars))
(names (-distinct (-map 'js2-name-node-name local)))
(declared-in-exprs (-map #'js2r--var-init-node-target-name (-mapcat #'js2r--var-init-node-decendants exprs)))
(outside-exprs (-difference (js2-block-node-kids block) exprs))
(outside-var-uses (-map #'js2-name-node-name (-mapcat #'js2r--name-node-decendants outside-exprs)))
(declared-in-but-used-outside (-intersection declared-in-exprs outside-var-uses))
(export-var (car declared-in-but-used-outside))
(params (-difference names declared-in-exprs))
(params-string (mapconcat #'identity (reverse params) ", "))
(first (car exprs))
(last (car (last exprs)))
(beg (js2-node-abs-pos (car exprs)))
(end (js2-node-abs-end last))
(contents (buffer-substring beg end)))
(goto-char beg)
(delete-region beg end)
(when (js2-return-node-p last)
(insert "return "))
(when export-var
(setq contents (concat contents "\nreturn " export-var ";"))
(insert "var " export-var " = "))
(insert (format call-template name params-string))
(goto-char (js2-node-abs-pos fn))
(when goto-position (funcall goto-position))
(let ((start (point)))
(insert (format function-template name params-string contents))
(indent-region start (1+ (point))))))))