6 (defconst js2-imenu-extension-styles
8 :call-re "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
9 :recorder js2-imenu-record-jquery-extend)
12 :call-re "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
13 :recorder js2-imenu-record-string-declare)
16 :call-re "^\\s-*dojo.declare\\s-*("
17 :recorder js2-imenu-record-string-declare)
20 :call-re ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
21 :recorder js2-imenu-record-backbone-extend)))
23 (defconst js2-imenu-available-frameworks
24 (mapcar (lambda (style) (plist-get style :framework)) js2-imenu-extension-styles)
25 "List of available JavaScript framework symbols.")
27 (defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
28 "Frameworks to be recognized by `js2-mode'."
29 :type (cons 'set (mapcar (lambda (x) (list 'const x))
30 js2-imenu-available-frameworks))
33 (defcustom js2-imenu-show-other-functions t
34 "Non-nil to show functions not recognized by other mechanisms,
35 in a shared namespace."
39 (defcustom js2-imenu-other-functions-ns "?"
40 "Namespace name to use for other functions."
44 (defun js2-imenu-extras-setup ()
45 (when js2-imenu-enabled-frameworks
46 (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
47 (when js2-imenu-show-other-functions
48 (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-hashes t)))
50 (declare (special root))
52 (defun js2-imenu-record-declarations ()
53 (let* ((styles (loop for style in js2-imenu-extension-styles
54 when (memq (plist-get style :framework)
55 js2-imenu-enabled-frameworks)
57 (re (mapconcat (lambda (style)
58 (concat "\\(" (plist-get style :call-re) "\\)"))
60 ;; Dynamic scoping. Ew.
62 (goto-char (point-min))
63 (while (js-re-search-forward re nil t)
64 (loop for i from 0 to (1- (length styles))
65 when (match-beginning (1+ i))
66 return (funcall (plist-get (nth i styles) :recorder))))))
68 (defun js2-imenu-record-jquery-extend ()
69 (let ((pred (lambda (subject)
71 (js2-prop-get-node-p subject)
72 (string= (js2-name-node-name (js2-prop-get-node-right subject))
74 (js2-imenu-record-extend-first-arg (1- (point)) pred
75 'js2-compute-nested-prop-get)))
77 (defun js2-imenu-record-string-declare ()
78 (js2-imenu-record-extend-first-arg
79 (1- (point)) 'js2-string-node-p
80 (lambda (node) (split-string (js2-string-node-value node) "\\." t))))
82 (defun js2-imenu-record-extend-first-arg (point pred qname-fn)
83 (let* ((node (js2-node-at-point point))
84 (args (js2-call-node-args node))
85 (subject (first args)))
86 (when (funcall pred subject)
87 (loop for arg in (cdr args)
88 when (js2-object-node-p arg)
89 do (js2-record-object-literal
90 arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
92 (defun js2-imenu-record-backbone-extend ()
93 (let* ((node (js2-node-at-point (1- (point))))
94 (args (js2-call-node-args node))
95 (methods (first args))
96 (parent (js2-node-parent node)))
97 (when (js2-object-node-p methods)
98 (let ((subject (cond ((js2-var-init-node-p parent)
99 (js2-var-init-node-target parent))
100 ((js2-assign-node-p parent)
101 (js2-assign-node-left parent)))))
103 (js2-record-object-literal methods
104 (js2-compute-nested-prop-get subject)
105 (js2-node-abs-pos methods)))))))
107 (defun js2-imenu-record-hashes ()
112 (if (and (js2-object-prop-node-p node)
113 (js2-function-node-p (js2-object-prop-node-right node)))
114 (let ((fn-node (js2-object-prop-node-right node)))
115 (unless (and js2-imenu-function-map
116 (gethash fn-node js2-imenu-function-map))
117 (let ((key-node (js2-object-prop-node-left node)))
118 (js2-record-imenu-entry fn-node
119 (list js2-imenu-other-functions-ns
120 (js2-prop-node-name key-node))
121 (js2-node-abs-pos key-node))))
125 (provide 'js2-imenu-extras)