]> code.delx.au - gnu-emacs/commitdiff
Maintain ordering of JSON object keys by default
authorSimen Heggestøyl <simenheg@gmail.com>
Sat, 3 Oct 2015 21:52:36 +0000 (23:52 +0200)
committerSimen Heggestøyl <simenheg@gmail.com>
Sat, 3 Oct 2015 21:52:36 +0000 (23:52 +0200)
* 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.

etc/NEWS
lisp/json.el
test/automated/json-tests.el

index 26c478eff730052dfff1e4d4fbae352ceb3d01d9..dbe0de38db67132b3f278f657d8bb3467f0b0991 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -314,6 +314,11 @@ standards.
 \f
 * 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'
 ** Prog mode has some support for multi-mode indentation.
 See `prog-indentation-context' and `prog-widen'.
index daa0c94da282eaa9e436fa5a3505d53a1b56756c..e2c7cc77222bbe8cb9bebd88fc3abe37344242ee 100644 (file)
@@ -57,7 +57,8 @@
 (defvar json-object-type 'alist
   "Type to convert JSON objects to.
 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
   "Type to convert JSON arrays to.
@@ -136,6 +137,17 @@ without indentation.")
                  'not-plist)))
   (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)
   `(let ((json--encoding-current-indentation
           (if json-encoding-pretty-print
@@ -400,7 +412,10 @@ Please see the documentation of `json-object-type' and `json-key-type'."
           (signal 'json-object-format (list "," (json-peek))))))
     ;; Skip over the "}"
     (json-advance)
-    elements))
+    (pcase json-object-type
+      (`alist (nreverse elements))
+      (`plist (json--plist-reverse elements))
+      (_ elements))))
 
 ;; Hash table encoding
 
@@ -602,6 +617,8 @@ Advances point just past JSON object."
   (interactive "r")
   (atomic-change-group
     (let ((json-encoding-pretty-print t)
+          ;; Ensure that ordering is maintained
+          (json-object-type 'alist)
           (txt (delete-and-extract-region begin end)))
       (insert (json-encode (json-read-from-string txt))))))
 
index fd89b7aa994e608006d570fa41d8e887e2258340..d1b7a2fa022c1f56470f16a9e90919ff904054cc 100644 (file)
 (require 'ert)
 (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 ()
   (should (equal (json-encode '((a . 1)
                                 (b . 2)))
                  "{\"a\":1,\"b\":2}")))
 
 (ert-deftest json-read-simple-alist ()
-  (should (equal (json-read-from-string "{\"a\": 1, \"b\": 2}")
-                 '((b . 2)
-                   (a . 1)))))
+  (let ((json-object-type 'alist))
+    (should (equal (json-read-from-string "{\"a\": 1, \"b\": 2}")
+                   '((a . 1)
+                     (b . 2))))))
 
 (ert-deftest json-encode-string-with-special-chars ()
   (should (equal (json-encode-string "a\n\fb")