[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 98433fb 036/110: `js2-print-json-path' added
From: |
Dmitry Gutov |
Subject: |
[elpa] master 98433fb 036/110: `js2-print-json-path' added |
Date: |
Thu, 23 Jun 2016 01:12:55 +0000 (UTC) |
branch: master
commit 98433fb95422ffcdc8e9ac41ed4052029490f01c
Author: Chen Bin <address@hidden>
Commit: Chen Bin <address@hidden>
`js2-print-json-path' added
---
js2-mode.el | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/json-path.el | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+)
diff --git a/js2-mode.el b/js2-mode.el
index 0f17c16..3566071 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10878,6 +10878,67 @@ And, if CHECK-ACTIVATION-P is non-nil, use the value
of TOKEN."
(js2-check-activation-name s (or token js2-NAME)))
name))
+;;; Use AST to extract semantic information
+
+(defun js2-get-element-index-from-array-node (elem array-node &optional
hardcoded-array-index)
+ "Get index of ELEM from ARRAY-NODE or 0 and return it as string."
+ (let ((idx 0) elems (rlt hardcoded-array-index))
+ (setq elems (js2-array-node-elems array-node))
+ (if (and elem (not hardcoded-array-index))
+ (setq rlt (catch 'nth-elt
+ (dolist (x elems)
+ ;; We know the ELEM does belong to ARRAY-NODE,
+ (if (eq elem x) (throw 'nth-elt idx))
+ (setq idx (1+ idx)))
+ 0)))
+ (format "[%s]" rlt)))
+
+(defun js2-print-json-path (&optional hardcoded-array-index)
+ "Print the path to the JSON value under point, and save it in the kill ring.
+If HARDCODED-ARRAY-INDEX provided, array index in JSON path is replaced with
it."
+ (interactive "P")
+ (let (previous-node current-node
+ key-name
+ rlt)
+
+ ;; The `js2-node-at-point' starts scanning from AST root node.
+ ;; So there is no way to optimize it.
+ (setq current-node (js2-node-at-point))
+
+ (while (not (js2-ast-root-p current-node))
+ (cond
+ ;; JSON property node
+ ((js2-object-prop-node-p current-node)
+ (setq key-name (js2-prop-node-name (js2-object-prop-node-left
current-node)))
+ (if rlt (setq rlt (concat "." key-name rlt))
+ (setq rlt (concat "." key-name))))
+
+ ;; Array node
+ ((or (js2-array-node-p current-node))
+ (setq rlt (concat (js2-get-element-index-from-array-node previous-node
+ current-node
+
hardcoded-array-index)
+ rlt)))
+
+ ;; Other nodes are ignored
+ (t))
+
+ ;; current node is archived
+ (setq previous-node current-node)
+ ;; Get parent node and continue the loop
+ (setq current-node (js2-node-parent current-node)))
+
+ (cond
+ (rlt
+ ;; Clean the final result
+ (setq rlt (replace-regexp-in-string "^\\." "" rlt))
+ (kill-new rlt)
+ (message "%s => kill-ring" rlt))
+ (t
+ (message "No JSON path found!")))
+
+ rlt))
+
;;; Indentation support (bouncing)
;; In recent-enough Emacs, we reuse the indentation code from
diff --git a/tests/json-path.el b/tests/json-path.el
new file mode 100644
index 0000000..70aecef
--- /dev/null
+++ b/tests/json-path.el
@@ -0,0 +1,64 @@
+;;; tests/json-path.el --- Test of using js2-mode AST to print JSON path.
+
+;; Copyright (C) 2015 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'js2-mode)
+
+(ert-deftest js2-json-path-with-actual-array-index ()
+ (with-temp-buffer
+ (insert "var a = { hello: [1, 2, [1,3,3,4, { world: { hell: { yes: [1,2,
'test'] } } }]] };")
+ (js2-mode)
+ (goto-char 0)
+ (search-forward "test")
+ (should (string= (js2-print-json-path) "hello[2][4].world.hell.yes[2]"))))
+
+(ert-deftest js2-json-path-pure-arrays ()
+ (with-temp-buffer
+ (insert "var a = [5, 1, 4, [ 4, [1, 2, [1, 3.9, 4, [1, 2, 'test',3]]]], 9,
9];")
+ (js2-mode)
+ (goto-char 0)
+ (search-forward "test")
+ (should (string= (js2-print-json-path) "[3][1][2][3][2]"))))
+
+(ert-deftest js2-json-path-key-is-numeric ()
+ (with-temp-buffer
+ (insert "var b = {hello: {3 : {world: {2: 'test'}}}};")
+ (js2-mode)
+ (goto-char 0)
+ (search-forward "test")
+ (should (string= (js2-print-json-path) "hello.3.world.2"))))
+
+(ert-deftest js2-json-path-not-found ()
+ (with-temp-buffer
+ (insert "console.log('test');")
+ (js2-mode)
+ (goto-char 0)
+ (search-forward "test")
+ (should (eq (js2-print-json-path) nil))))
+
+(ert-deftest js2-json-path-with-array-index-hardcoded ()
+ (with-temp-buffer
+ (insert "var a = { hello: [1, 2, [1,3,3,4, { world: { hell: { yes: [1,2,
'test'] } } }]] };")
+ (js2-mode)
+ (goto-char 0)
+ (search-forward "test")
+ (should (string= (js2-print-json-path 1) "hello[1][1].world.hell.yes[1]"))
+ (should (string= (js2-print-json-path 0)
"hello[0][0].world.hell.yes[0]"))))
- [elpa] master 1f95553 033/110: Add js2-jsx-mode usage instructions, (continued)
- [elpa] master 1f95553 033/110: Add js2-jsx-mode usage instructions, Dmitry Gutov, 2016/06/22
- [elpa] master 47b215d 011/110: Define js2-object-property face, Dmitry Gutov, 2016/06/22
- [elpa] master c0e0309 022/110: Allow semicolons in a class body, Dmitry Gutov, 2016/06/22
- [elpa] master df3f97f 030/110: Add js2-jsx-mode, Dmitry Gutov, 2016/06/22
- [elpa] master 6aba571 021/110: Merge pull request #276 from XeCycle/methods, Dmitry Gutov, 2016/06/22
- [elpa] master 221282a 028/110: Merge pull request #280 from XeCycle/binding-pattern-initializer, Dmitry Gutov, 2016/06/22
- [elpa] master 2e7fdb3 012/110: Also highlight property lookups with the same face, Dmitry Gutov, 2016/06/22
- [elpa] master b1234ca 013/110: Don't misindent generator methods, Dmitry Gutov, 2016/06/22
- [elpa] master d82a58d 019/110: Refactor: rename getter-setter-node to method-node, Dmitry Gutov, 2016/06/22
- [elpa] master 263852b 026/110: Add melpa badges, Dmitry Gutov, 2016/06/22
- [elpa] master 98433fb 036/110: `js2-print-json-path' added,
Dmitry Gutov <=
- [elpa] master f9d28d3 052/110: Adjust js2-print-export-node, Dmitry Gutov, 2016/06/22
- [elpa] master d307285 039/110: Move method type handling to property METHOD_TYPE, Dmitry Gutov, 2016/06/22
- [elpa] master f652d17 044/110: Add setImmediate and clearImmediate to js2-node-externs, Dmitry Gutov, 2016/06/22
- [elpa] master e0972fb 048/110: s/will/would, Dmitry Gutov, 2016/06/22
- [elpa] master d201a30 027/110: Merge pull request #281 from robbyoconnor/patch-1, Dmitry Gutov, 2016/06/22
- [elpa] master 667d320 034/110: Merge pull request #282 from jacksonrayhamilton/js2-jsx-mode, Dmitry Gutov, 2016/06/22
- [elpa] master 29f74b1 040/110: Allow 0o octals in strict mode, Dmitry Gutov, 2016/06/22
- [elpa] master 2a22635 035/110: Support .jsx file extension too in the example, Dmitry Gutov, 2016/06/22
- [elpa] master 4955584 037/110: Merge pull request #278 from redguardtoo/master, Dmitry Gutov, 2016/06/22
- [elpa] master 7c12f2c 031/110: Copy JSX indentation logic to js2-old-indent.el, Dmitry Gutov, 2016/06/22