[Git][clojure-team/clj-yaml-clojure][upstream] New upstream version 0.7.2

Jérôme Charaoui (@lavamind) gitlab at salsa.debian.org
Sun Feb 5 22:09:17 GMT 2023



Jérôme Charaoui pushed to branch upstream at Debian Clojure Maintainers / clj-yaml-clojure


Commits:
29400c2f by Jérôme Charaoui at 2023-02-05T16:31:35-05:00
New upstream version 0.7.2
- - - - -


9 changed files:

- + .circleci/config.yml
- .gitignore
- + CHANGELOG.md
- README.md
- project.clj
- − src/clj_yaml/core.clj
- + src/clojure/clj_yaml/core.clj
- + src/java/clj_yaml/MarkedConstructor.java
- test/clj_yaml/core_test.clj


Changes:

=====================================
.circleci/config.yml
=====================================
@@ -0,0 +1,17 @@
+version: 2.1
+jobs:
+  test:
+    docker:
+      - image: circleci/clojure:lein-2.8.1
+    steps:
+      - checkout
+      - run:
+          name: Ensure No Reflection Warnings
+          command: "! lein check 2>&1 | grep 'Reflection warning'"
+      - run: lein test
+
+
+workflows:
+  workflow:
+    jobs:
+      - test


=====================================
.gitignore
=====================================
@@ -1,5 +1,6 @@
+bin
 lib
 classes
 *.jar
-.*
-pom.xml
+pom.xml*
+/target


=====================================
CHANGELOG.md
=====================================
@@ -0,0 +1,17 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+
+## [0.7.0] - 2019-03-15
+### Changed
+- [Accept emoji](https://github.com/clj-commons/clj-yaml/pull/5).
+- [Update to SnakeYAML from 1.23 to 1.24](https://github.com/clj-commons/clj-yaml/pull/5).
+
+## [0.6.1] - 2019-02-06
+### Changed
+- [Restore default text-wrapping behavior of prior release](https://github.com/clj-commons/clj-yaml/pull/2).
+
+## [0.6.0] - 2019-01-04
+### Added
+- First release under [clj-commons](https://github.com/clj-commons) project.


=====================================
README.md
=====================================
@@ -1,33 +1,71 @@
-`clj-yaml` provides [YAML](http://yaml.org) encoding and decoding for Clojure via the [SnakeYAML](http://code.google.com/p/snakeyaml/) Java library.
+`clj-commons/clj-yaml` provides [YAML](http://yaml.org) encoding and
+decoding for Clojure via the [snakeyaml][] Java library.
+
+[SnakeYAML]: https://bitbucket.org/asomov/snakeyaml/
+
+
+[![Clojars Project](https://img.shields.io/clojars/v/clj-commons/clj-yaml.svg)](https://clojars.org/clj-commons/clj-yaml) [![cljdoc badge](https://cljdoc.org/badge/clj-commons/clj-yaml)](https://cljdoc.org/d/clj-commons/clj-yaml/CURRENT)
+ [![CircleCI Status](https://circleci.com/gh/clj-commons/clj-yaml.svg?style=svg)](https://circleci.com/gh/clj-commons/clj-yaml)
+
+(This is a maintained fork of [the original][]).
+
+[the original]: https://github.com/lancepantz/clj-yaml
+
 
 ## Usage
 
-    (require '[clj-yaml.core :as yaml])
-    
-    (yaml/generate-string
-      [{:name "John Smith", :age 33}
-       {:name "Mary Smith", :age 27}])
-    "- {name: John Smith, age: 33}\n- {name: Mary Smith, age: 27}\n"
-
-    (yaml/parse-string "
-    - {name: John Smith, age: 33}
-    - name: Mary Smith
-      age: 27
-    ")
-    => ({:name "John Smith", :age 33}
-        {:name "Mary Smith", :age 27})
+```clojure
+(require '[clj-yaml.core :as yaml])
+
+(yaml/generate-string
+  [{:name "John Smith", :age 33}
+   {:name "Mary Smith", :age 27}])
+"- {name: John Smith, age: 33}\n- {name: Mary Smith, age: 27}\n"
+
+(yaml/parse-string "
+- {name: John Smith, age: 33}
+- name: Mary Smith
+  age: 27
+")
+=> ({:name "John Smith", :age 33}
+    {:name "Mary Smith", :age 27})
+```
+
+By default, keys are converted to clojure keywords.  To prevent this,
+add `:keywords false` parameters to the `parse-string` function:
+
+```clojure
+(yaml/parse-string "
+- {name: John Smith}
+" :keywords false)
+```
+
+Different flow styles (`:auto`, `:block`, `:flow`) allow customization of how YAML is rendered:
+
+
+```clojure
+(yaml/generate-string some-data :dumper-options {:flow-style :block})
+```
 
 ## Installation
 
-`clj-yaml` is available as a Maven artifact from [Clojars](http://clojars.org/clj-yaml):
+`clj-commons/clj-yaml` is available as a Maven artifact from [Clojars](http://clojars.org/clj-commons/clj-yaml).
+
+### Leiningen/Boot
+
+```clojure
+[clj-commons/clj-yaml "0.7.0"]
+```
+
+### Clojure CLI/`deps.edn`
 
-    :dependencies
-      [["clj-yaml" "0.4.0"]
-       ...]
+```clojure
+clj-commons/clj-yaml {:mvn/version "0.7.0"}
+```
 
 ## Development
 
-    $ git clone git://github.com/lancepantz/clj-yaml.git
+    $ git clone git://github.com/clj-commons/clj-yaml.git
     $ lein deps
     $ lein test
     $ lein install


=====================================
project.clj
=====================================
@@ -1,6 +1,16 @@
-(defproject clj-yaml "0.4.0"
+(defproject clj-commons/clj-yaml "0.7.2"
   :description "YAML encoding and decoding for Clojure using SnakeYAML"
-  :url "http://github.com/lancepantz/clj-yaml"
+  :url "https://github.com/clj-commons/clj-yaml"
+  :license {:name "Eclipse Public License - v 1.0"
+            :url "http://www.eclipse.org/legal/epl-v10.html"
+            :distribution :repo
+            :comments "Same as Clojure"}
+  ;; Emit warnings on all reflection calls.
+  :global-vars {*warn-on-reflection* true}
+  :source-paths ["src/clojure"]
+  :java-source-paths ["src/java"]
+  :javac-options ["-target" "1.7" "-source" "1.7" "-Xlint:-options"]
   :dependencies
-    [[org.clojure/clojure "1.2.0"]
-     [org.yaml/snakeyaml "1.5"]])
+  [[org.yaml/snakeyaml "1.26"]
+   [org.flatland/ordered "1.5.9"]]
+  :profiles {:provided {:dependencies [[org.clojure/clojure "1.10.1"]]}})


=====================================
src/clj_yaml/core.clj deleted
=====================================
@@ -1,78 +0,0 @@
-(ns clj-yaml.core
-  (:import (org.yaml.snakeyaml Yaml DumperOptions DumperOptions$FlowStyle)))
-
-(def ^{:dynamic true} *keywordize* true)
-
-(def flow-styles
-  {:auto DumperOptions$FlowStyle/AUTO
-   :block DumperOptions$FlowStyle/BLOCK
-   :flow DumperOptions$FlowStyle/FLOW})
-
-(defn make-dumper-options
-  [& {:keys [flow-style]}]
-  (doto (DumperOptions.)
-    (.setDefaultFlowStyle (flow-styles flow-style))))
-
-(defn make-yaml
-  [& {:keys [dumper-options]}]
-  (if dumper-options
-    (Yaml. (apply make-dumper-options
-                  (mapcat (juxt key val)
-                          dumper-options)))
-    (Yaml.)))
-
-(defprotocol YAMLCodec
-  (encode [data])
-  (decode [data]))
-
-(defn decode-key [k]
-  (if *keywordize* (keyword k) k))
-
-(extend-protocol YAMLCodec
-
-  clojure.lang.IPersistentMap
-  (encode [data]
-    (into {}
-          (for [[k v] data]
-            [(encode k) (encode v)])))
-
-  clojure.lang.IPersistentCollection
-  (encode [data]
-    (map encode data))
-
-  clojure.lang.Keyword
-  (encode [data]
-    (name data))
-
-  java.util.LinkedHashMap
-  (decode [data]
-    (into {}
-          (for [[k v] data]
-            [(decode-key k) (decode v)])))
-
-  java.util.LinkedHashSet
-  (decode [data]
-    (into #{} data))
-
-  java.util.ArrayList
-  (decode [data]
-    (map decode data))
-
-  Object
-  (encode [data] data)
-  (decode [data] data)
-
-  nil
-  (encode [data] data)
-  (decode [data] data))
-
-(defn generate-string [data & opts]
-  (.dump (apply make-yaml opts)
-         (encode data)))
-
-(defn parse-string
-  ([string keywordize]
-     (binding [*keywordize* keywordize]
-       (parse-string string)))
-  ([string]
-     (decode (.load (make-yaml) string))))


=====================================
src/clojure/clj_yaml/core.clj
=====================================
@@ -0,0 +1,158 @@
+(ns clj-yaml.core
+  (:require [flatland.ordered.map :refer (ordered-map)]
+            [flatland.ordered.set :refer (ordered-set)])
+  (:import (org.yaml.snakeyaml Yaml DumperOptions DumperOptions$FlowStyle LoaderOptions)
+           (org.yaml.snakeyaml.constructor Constructor SafeConstructor BaseConstructor)
+           (org.yaml.snakeyaml.representer Representer)
+           (org.yaml.snakeyaml.error Mark)
+           (clj_yaml MarkedConstructor)
+           (java.util LinkedHashMap)))
+
+(def flow-styles
+  {:auto DumperOptions$FlowStyle/AUTO
+   :block DumperOptions$FlowStyle/BLOCK
+   :flow DumperOptions$FlowStyle/FLOW})
+
+(defn ^DumperOptions default-dumper-options
+  "clj-yaml 0.5.6 used SnakeYAML 1.13 which by default did *not* split long
+  lines. clj-yaml 0.6.0 upgraded to SnakeYAML 1.23 which by default *did* split
+  long lines. This ensures that generate-string uses the older behavior by
+  default, for the sake of stability, i.e. backwards compatibility."
+  []
+  (doto (DumperOptions.)
+    (.setSplitLines false)))
+
+(defn ^DumperOptions make-dumper-options
+  [& {:keys [flow-style]}]
+  (doto (default-dumper-options)
+    (.setDefaultFlowStyle (flow-styles flow-style))))
+
+(defn ^LoaderOptions default-loader-options
+  []
+  (LoaderOptions.))
+
+(defn ^LoaderOptions make-loader-options
+  [& {:keys [max-aliases-for-collections allow-recursive-keys allow-duplicate-keys]}]
+  (let [loader (default-loader-options)]
+    (when max-aliases-for-collections
+      (.setMaxAliasesForCollections loader max-aliases-for-collections))
+    (when allow-recursive-keys
+      (.setAllowRecursiveKeys loader allow-recursive-keys))
+    (when (instance? Boolean allow-duplicate-keys)
+      (.setAllowDuplicateKeys loader allow-duplicate-keys))
+    loader))
+
+(defn ^Yaml make-yaml
+  "Make a yaml encoder/decoder with some given options."
+  [& {:keys [dumper-options unsafe mark max-aliases-for-collections allow-recursive-keys allow-duplicate-keys]}]
+  (let [loader (make-loader-options :max-aliases-for-collections max-aliases-for-collections
+                                    :allow-recursive-keys allow-recursive-keys
+                                    :allow-duplicate-keys allow-duplicate-keys)
+        ^BaseConstructor constructor
+        (if unsafe (Constructor. loader)
+            (if mark
+              ;; construct2ndStep isn't implemented by MarkedConstructor,
+              ;; causing an exception to be thrown before loader options are
+              ;; used
+              (MarkedConstructor.)
+              (SafeConstructor. loader)))
+        ;; TODO: unsafe marked constructor
+        dumper (if dumper-options
+                 (make-dumper-options :flow-style (:flow-style dumper-options))
+                 (default-dumper-options))]
+    (Yaml. constructor (Representer.) dumper loader)))
+
+(defrecord Marked
+  [start end unmark])
+
+(defn mark
+  "Mark some data with start and end positions."
+  [start end marked]
+  (Marked. start end marked))
+
+(defn marked?
+  "Let us know whether this piece of data is marked with source positions."
+  [m]
+  (instance? Marked m))
+
+(defn unmark
+  "Strip the source information from this piece of data, if it exists."
+  [m]
+  (if (marked? m)
+    (:unmark m)
+    m))
+
+(defprotocol YAMLCodec
+  "A protocol for things that can be coerced to and from the types
+   that snakeyaml knows how to encode and decode."
+  (encode [data])
+  (decode [data keywords]))
+
+(extend-protocol YAMLCodec
+  clj_yaml.MarkedConstructor$Marked
+  (decode [data keywords]
+    (letfn [(from-Mark [^Mark mark]
+              {:line (.getLine mark)
+               :index (.getIndex mark)
+               :column (.getColumn mark)})]
+      ;; Decode the marked data and rewrap it with its source position.
+      (mark (-> data .start from-Mark)
+            (-> data .end from-Mark)
+            (-> data .marked
+                (decode keywords)))))
+
+  clojure.lang.IPersistentMap
+  (encode [data]
+    (let [lhm (LinkedHashMap.)]
+      (doseq [[k v] data]
+        (.put lhm (encode k) (encode v)))
+      lhm))
+
+  clojure.lang.IPersistentCollection
+  (encode [data]
+    (map encode data))
+
+  clojure.lang.Keyword
+  (encode [data]
+    (name data))
+
+  java.util.LinkedHashMap
+  (decode [data keywords]
+    (letfn [(decode-key [k]
+              (if keywords
+                ;; (keyword k) is nil for numbers etc
+                (or (keyword k) k)
+                k))]
+      (into (ordered-map)
+            (for [[k v] data]
+              [(-> k (decode keywords) decode-key) (decode v keywords)]))))
+
+  java.util.LinkedHashSet
+  (decode [data keywords]
+    (into (ordered-set) data))
+
+  java.util.ArrayList
+  (decode [data keywords]
+    (map #(decode % keywords) data))
+
+  Object
+  (encode [data] data)
+  (decode [data keywords] data)
+
+  nil
+  (encode [data] data)
+  (decode [data keywords] data))
+
+
+(defn generate-string [data & opts]
+  (.dump ^Yaml (apply make-yaml opts)
+         (encode data)))
+
+(defn parse-string
+  [^String string & {:keys [unsafe mark keywords max-aliases-for-collections allow-recursive-keys allow-duplicate-keys] :or {keywords true}}]
+  (decode (.load (make-yaml :unsafe unsafe
+                            :mark mark
+                            :max-aliases-for-collections max-aliases-for-collections
+                            :allow-recursive-keys allow-recursive-keys
+                            :allow-duplicate-keys allow-duplicate-keys)
+                 string) keywords))


=====================================
src/java/clj_yaml/MarkedConstructor.java
=====================================
@@ -0,0 +1,61 @@
+package clj_yaml;
+
+import org.yaml.snakeyaml.constructor.Construct;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
+import org.yaml.snakeyaml.constructor.AbstractConstruct;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.error.Mark;
+
+/* A subclass of SafeConstructor that wraps all the type-specific
+   constructors it defines with versions that mark the start and
+   end positions.
+*/
+public class MarkedConstructor extends SafeConstructor {
+    /* The types we want to wrap. */
+    public static Tag[] tags = {Tag.NULL, Tag.BOOL, Tag.INT, Tag.FLOAT,
+                                Tag.BINARY, Tag.TIMESTAMP, Tag.OMAP,
+                                Tag.PAIRS, Tag.SET, Tag.STR, Tag.SEQ, Tag.MAP};
+
+    public MarkedConstructor() {
+        // Make sure SafeConstructor's constructor is called first,
+        // so that we overwrite the keys that SafeConstructor sets.
+        super();
+        // Wrap all the constructors with Marking constructors.
+        for (Tag tag : tags) {
+            Construct old = this.yamlConstructors.get(tag);
+            this.yamlConstructors.put(tag, new Marking(old));
+        }
+    }
+    /* An intermediate representation of data marked with start and
+       end positions before we turn it into the nice clojure thing.
+    */
+    public static class Marked {
+        /* An object paired with start and end Marks. */
+        public Mark start;
+        public Mark end;
+        public Object marked;
+        public Marked(Mark start, Mark end, Object marked) {
+            this.start = start;
+            this.end = end;
+            this.marked = marked;
+        }
+    }
+
+    /* A wrapper around a Construct that marks source positions before calling
+       the original.
+     */
+    public class Marking extends AbstractConstruct {
+        public Construct constructor;
+        public Marking(Construct constructor) {
+            this.constructor = constructor;
+        }
+        public Object construct(Node node) {
+            return new Marked
+                (node.getStartMark(),
+                 node.getEndMark(),
+                 constructor.construct(node));
+        }
+    }
+}


=====================================
test/clj_yaml/core_test.clj
=====================================
@@ -1,6 +1,10 @@
 (ns clj-yaml.core-test
-  (:use clojure.test)
-  (:use clj-yaml.core))
+  (:require [clojure.test :refer (deftest testing is)]
+            [clojure.string :as string]
+            [clj-yaml.core :refer [parse-string unmark generate-string]])
+  (:import [java.util Date]
+           (org.yaml.snakeyaml.error YAMLException)
+           (org.yaml.snakeyaml.constructor DuplicateKeyException)))
 
 (def nested-hash-yaml
   "root:\n  childa: a\n  childb: \n    grandchild: \n      greatgrandchild: bar\n")
@@ -24,8 +28,8 @@ items:
       - Wicked Witch of the East
 ")
 
-(def inline-list-yaml "
---- # Shopping list
+(def inline-list-yaml
+"--- # Shopping list
 [milk, pumpkin pie, eggs, juice]
 ")
 
@@ -48,6 +52,9 @@ women:
 (def typed-data-yaml "
 the-bin: !!binary 0101")
 
+(def io-file-typed-data-yaml "
+!!java.io.File")
+
 (def set-yaml "
 --- !!set
 ? Mark McGwire
@@ -58,6 +65,14 @@ the-bin: !!binary 0101")
   (let [parsed (parse-string "foo: bar")]
     (is (= "bar" (parsed :foo)))))
 
+(deftest parse-hash-with-numeric-key
+  (let [parsed (parse-string "123: 456")]
+    (is (= 456 (parsed 123)))))
+
+(deftest parse-hash-with-complex-key
+  (let [parsed (parse-string "[1, 2]: 3")]
+    (is (= 3 (parsed [1, 2])))))
+
 (deftest parse-nested-hash
   (let [parsed (parse-string nested-hash-yaml)]
     (is (= "a"   ((parsed :root) :childa)))
@@ -108,14 +123,110 @@ the-bin: !!binary 0101")
   (let [parsed (parse-string typed-data-yaml)]
     (is (= (Class/forName "[B") (type (:the-bin parsed))))))
 
+(deftest disallow-arbitrary-typed-data
+  (is (thrown? org.yaml.snakeyaml.error.YAMLException
+               (parse-string io-file-typed-data-yaml))))
+
 (deftest keywordized
-  (binding [*keywordize* false]
-    (is  (= "items" (-> hashes-lists-yaml parse-string ffirst))))
-  (is  (= "items" (-> hashes-lists-yaml (parse-string false) ffirst))))
+  (is (= "items"
+         (-> hashes-lists-yaml
+             (parse-string :keywords false)
+             ffirst))))
+
+(deftest not-keywordized-in-lists
+  (is (every? string?
+              (-> "[{b: c, c: d}]"
+                  (parse-string :keywords false)
+                  first
+                  keys))))
+
+(deftest marking-source-position-works
+  (let [parsed (parse-string inline-list-yaml :mark true)]
+    ;; The list starts at the beginning of line 1.
+    (is (= 1 (-> parsed :start :line)))
+    (is (= 0 (-> parsed :start :column)))
+    ;; The first item starts at the second character of line 1.
+    (is (= 1 (-> parsed unmark first :start :line)))
+    (is (= 1 (-> parsed unmark first :start :column)))
+    ;; The first item ends at the fifth character of line 1.
+    (is (= 1 (-> parsed unmark first :end :line)))
+    (is (= 5 (-> parsed unmark first :end :column)))))
+
+(deftest text-wrapping
+  (let [data
+        {:description
+         "Big-picture diagram showing how our top-level systems and stakeholders interact"}]
+    (testing "long lines of text should not be wrapped"
+      ;; clj-yaml 0.5.6 used SnakeYAML 1.13 which by default did *not* split long lines.
+      ;; clj-yaml 0.6.0 upgraded to SnakeYAML 1.23 which by default *did* split long lines.
+      ;; This test ensures that generate-string uses the older behavior by default, for the sake
+      ;; of stability, i.e. backwards compatibility.
+      (is
+        (= "{description: Big-picture diagram showing how our top-level systems and stakeholders interact}\n"
+           (generate-string data))))))
 
 (deftest dump-opts
   (let [data [{:age 33 :name "jon"} {:age 44 :name "boo"}]]
     (is (= "- age: 33\n  name: jon\n- age: 44\n  name: boo\n"
            (generate-string data :dumper-options {:flow-style :block})))
     (is (= "[{age: 33, name: jon}, {age: 44, name: boo}]\n"
-           (generate-string data :dumper-options {:flow-style :flow})))))
\ No newline at end of file
+           (generate-string data :dumper-options {:flow-style :flow})))))
+
+(deftest parse-time
+  (testing "clj-time parses timestamps with more than millisecond precision correctly."
+    (let [timestamp "2001-11-23 15:02:31.123456 -04:00"
+          expected 1006542151123]
+      (is (= (.getTime ^Date (parse-string timestamp)) expected)))))
+
+(deftest maps-are-ordered
+  (let [parsed (parse-string hashes-lists-yaml)
+        [first second] (:items parsed)]
+    (is (= (keys first) '(:part_no :descrip :price :quantity)))
+    (is (= (keys second)'(:part_no :descrip :price :quantity :owners)))))
+
+
+(deftest nulls-are-fine
+  (testing "nil does not blow up"
+    (let [res (parse-string "- f:")]
+      (is (= [{:f nil}] res))
+      (is (str res)))))
+
+(deftest emoji-can-be-parsed
+  (let [yaml "{emoji: 💣}"]
+    (is (= yaml (-> yaml
+                    (generate-string)
+                    (parse-string)
+                    (string/trim)))))
+
+  (testing "emoji in comments are OK too"
+    (let [yaml "# 💣 emoji in a comment\n42"]
+      (is (= 42 (parse-string yaml))))))
+
+(def too-many-aliases
+  (->> (range 51)
+       (map #(str "b" % ": *a"))
+       (cons "a: &a [\"a\",\"a\"]")
+       (string/join "\n")))
+
+(deftest max-aliases-for-collections-works
+  (is (thrown-with-msg? YAMLException #"Number of aliases" (parse-string too-many-aliases)))
+  (is (parse-string too-many-aliases :max-aliases-for-collections 51)))
+
+(def recursive-yaml "
+---
+&A
+- *A: *A
+")
+
+(deftest allow-recursive-works
+  (is (thrown-with-msg? YAMLException #"Recursive" (parse-string recursive-yaml)))
+  (is (parse-string recursive-yaml :allow-recursive-keys true)))
+
+(def duplicate-keys-yaml "
+a: 1
+a: 1
+")
+
+(deftest allow-recursive-works
+  (is (parse-string duplicate-keys-yaml))
+  (is (thrown-with-msg? DuplicateKeyException #"found duplicate key" (parse-string duplicate-keys-yaml :allow-duplicate-keys false))))



View it on GitLab: https://salsa.debian.org/clojure-team/clj-yaml-clojure/-/commit/29400c2fd3b8376fe4c02ef4a6481d3215577296

-- 
View it on GitLab: https://salsa.debian.org/clojure-team/clj-yaml-clojure/-/commit/29400c2fd3b8376fe4c02ef4a6481d3215577296
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20230205/11239eb6/attachment.htm>


More information about the pkg-java-commits mailing list