Commit 6b663751 authored by Simen Heggestøyl's avatar Simen Heggestøyl
Browse files

Maintain ordering of JSON object keys by default

* lisp/json.el (json-object-type): Mention order handling in doc-string.
(json--plist-reverse): New utility function.
(json-read-object): Maintain ordering for alists and plists.
(json-pretty-print): Ensure that ordering is maintained.

* test/automated/json-tests.el (test-json-plist-reverse): New test for
`json--plist-reverse'.
(json-read-simple-alist): Update test to accommodate for changes in
`json-read-object'.

* etc/NEWS: Document the new behavior of the pretty printing functions.
parent 9a05f0ac
...@@ -314,6 +314,11 @@ standards. ...@@ -314,6 +314,11 @@ standards.
* Changes in Specialized Modes and Packages in Emacs 25.1 * Changes in Specialized Modes and Packages in Emacs 25.1
** JSON
---
*** `json-pretty-print' and `json-pretty-print-buffer' now maintain
the ordering of object keys by default.
** You can recompute the VC state of a file buffer with `M-x vc-refresh-state' ** You can recompute the VC state of a file buffer with `M-x vc-refresh-state'
** Prog mode has some support for multi-mode indentation. ** Prog mode has some support for multi-mode indentation.
See `prog-indentation-context' and `prog-widen'. See `prog-indentation-context' and `prog-widen'.
......
...@@ -57,7 +57,8 @@ ...@@ -57,7 +57,8 @@
(defvar json-object-type 'alist (defvar json-object-type 'alist
"Type to convert JSON objects to. "Type to convert JSON objects to.
Must be one of `alist', `plist', or `hash-table'. Consider let-binding Must be one of `alist', `plist', or `hash-table'. Consider let-binding
this around your call to `json-read' instead of `setq'ing it.") this around your call to `json-read' instead of `setq'ing it. Ordering
is maintained for `alist' and `plist', but not for `hash-table'.")
(defvar json-array-type 'vector (defvar json-array-type 'vector
"Type to convert JSON arrays to. "Type to convert JSON arrays to.
...@@ -136,6 +137,17 @@ without indentation.") ...@@ -136,6 +137,17 @@ without indentation.")
'not-plist))) 'not-plist)))
(null list)) (null list))
(defun json--plist-reverse (plist)
"Return a copy of PLIST in reverse order.
Unlike `reverse', this keeps the property-value pairs intact."
(let (res)
(while plist
(let ((prop (pop plist))
(val (pop plist)))
(push val res)
(push prop res)))
res))
(defmacro json--with-indentation (body) (defmacro json--with-indentation (body)
`(let ((json--encoding-current-indentation `(let ((json--encoding-current-indentation
(if json-encoding-pretty-print (if json-encoding-pretty-print
...@@ -400,7 +412,10 @@ Please see the documentation of `json-object-type' and `json-key-type'." ...@@ -400,7 +412,10 @@ Please see the documentation of `json-object-type' and `json-key-type'."
(signal 'json-object-format (list "," (json-peek)))))) (signal 'json-object-format (list "," (json-peek))))))
;; Skip over the "}" ;; Skip over the "}"
(json-advance) (json-advance)
elements)) (pcase json-object-type
(`alist (nreverse elements))
(`plist (json--plist-reverse elements))
(_ elements))))
;; Hash table encoding ;; Hash table encoding
...@@ -602,6 +617,8 @@ Advances point just past JSON object." ...@@ -602,6 +617,8 @@ Advances point just past JSON object."
(interactive "r") (interactive "r")
(atomic-change-group (atomic-change-group
(let ((json-encoding-pretty-print t) (let ((json-encoding-pretty-print t)
;; Ensure that ordering is maintained
(json-object-type 'alist)
(txt (delete-and-extract-region begin end))) (txt (delete-and-extract-region begin end)))
(insert (json-encode (json-read-from-string txt)))))) (insert (json-encode (json-read-from-string txt))))))
......
...@@ -22,15 +22,22 @@ ...@@ -22,15 +22,22 @@
(require 'ert) (require 'ert)
(require 'json) (require 'json)
(ert-deftest test-json-plist-reverse ()
(should (equal (json--plist-reverse '()) '()))
(should (equal (json--plist-reverse '(:a 1)) '(:a 1)))
(should (equal (json--plist-reverse '(:a 1 :b 2 :c 3))
'(:c 3 :b 2 :a 1))))
(ert-deftest json-encode-simple-alist () (ert-deftest json-encode-simple-alist ()
(should (equal (json-encode '((a . 1) (should (equal (json-encode '((a . 1)
(b . 2))) (b . 2)))
"{\"a\":1,\"b\":2}"))) "{\"a\":1,\"b\":2}")))
(ert-deftest json-read-simple-alist () (ert-deftest json-read-simple-alist ()
(let ((json-object-type 'alist))
(should (equal (json-read-from-string "{\"a\": 1, \"b\": 2}") (should (equal (json-read-from-string "{\"a\": 1, \"b\": 2}")
'((b . 2) '((a . 1)
(a . 1))))) (b . 2))))))
(ert-deftest json-encode-string-with-special-chars () (ert-deftest json-encode-string-with-special-chars ()
(should (equal (json-encode-string "a\n\fb") (should (equal (json-encode-string "a\n\fb")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment