packages feed

aeson-yaml 1.0.5.0 → 1.0.6.0

raw patch · 4 files changed

+81/−28 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Changelog +## 1.0.6.0 - 2020-02-27++### Changed++  - Don't quote simple strings containing spaces, e.g: hello world++  - Single-quote dates (like '2020-02-27') and bools ('true' / 'false')+ ## 1.0.5.0 - 2019-11-30  ### Fixed
aeson-yaml.cabal view
@@ -1,7 +1,7 @@ cabal-version: 1.12  name:           aeson-yaml-version:        1.0.5.0+version:        1.0.6.0 homepage:       https://github.com/clovyr/aeson-yaml bug-reports:    https://github.com/clovyr/aeson-yaml/issues author:         Patrick Nielsen
src/Data/Aeson/Yaml.hs view
@@ -24,7 +24,7 @@ import qualified Data.ByteString.Builder as ByteString.Builder import qualified Data.ByteString.Lazy as ByteString.Lazy import qualified Data.ByteString.Short as ByteString.Short-import Data.Char (isDigit)+import Data.Char (isAlpha, isDigit) import qualified Data.HashMap.Strict as HashMap import Data.List (intersperse, sortOn) import Data.Monoid ((<>), mconcat, mempty)@@ -120,18 +120,28 @@  encodeText :: Bool -> Bool -> Int -> Text -> Builder encodeText canMultiline alwaysQuote level s+  -- s is a value, not a map key, and contains newlines; can be inserted+  -- literally with `|` syntax   | canMultiline && "\n" `Text.isSuffixOf` s = encodeLines level (Text.lines s)-  | alwaysQuote && unquotable =-    bs "'" <> b (Text.Encoding.encodeUtf8 s) <> bs "'"+  -- s is a number, date, or boolString; single-quote+  | Text.all isNumberOrDateRelated s || isBoolString = singleQuote+  -- s should be quoted, AND s is not unsafe; single-quote+  | alwaysQuote && unquotable = singleQuote+  -- s should be quoted, OR s might be unsafe; double-quote   | alwaysQuote || not unquotable = bl $ Data.Aeson.encode s-  | otherwise = b (Text.Encoding.encodeUtf8 s)+  -- otherwise; no quotes+  | otherwise = noQuote   where-    unquotable =-      s /= "" &&-      not isSpecial &&-      isSafeAscii (Text.head s) &&-      not (Text.all isNumberOrDateRelated s) && Text.all isAllowed s-    isSpecial+    noQuote = b (Text.Encoding.encodeUtf8 s)+    singleQuote = bs "'" <> noQuote <> bs "'"+    headS = Text.head s+    unquotable -- s is unquotable if all are True+     =+      s /= "" && -- s is not empty+      Text.all isAllowed s && -- s consists of acceptable chars+      (Data.Char.isAlpha headS || -- head of s is a char in A-Z or a-z or indicates a filepath+       headS == '/')+    isBoolString       | Text.length s > 5 = False       | otherwise =         case Text.toLower s of@@ -143,9 +153,7 @@       (c >= 'A' && c <= 'Z') ||       (c >= '0' && c <= '9') || c == '/' || c == '_' || c == '.' || c == '='     isNumberOrDateRelated c = isDigit c || c == '.' || c == 'e' || c == '-'-    isAllowed c-      -- We don't include ' ' here to avoid sequences like " -" and ": "-     = isSafeAscii c || c == '-' || c == ':'+    isAllowed c = isSafeAscii c || c == '-' || c == ':' || c == ' '  encodeLines :: Int -> [Text] -> Builder encodeLines level ls =
test/Test/Data/Aeson/Yaml.hs view
@@ -20,19 +20,19 @@  import Data.Aeson.Yaml -data TestCase =-  TestCase-    { tcName :: String-    , tcInput :: Data.ByteString.Lazy.ByteString-    , tcOutput :: Data.ByteString.Lazy.ByteString-    , tcAlwaysQuote :: Bool-    }+data TestCase = TestCase+  { tcName :: String+  , tcInput :: Data.ByteString.Lazy.ByteString+  , tcOutput :: Data.ByteString.Lazy.ByteString+  , tcAlwaysQuote :: Bool+  }  testCases :: [TestCase]-testCases = [tcDataTypes, tcNestedListsAndObjects, tcQuoted, tcEmptyList]+testCases =+  [tcDataTypes, tcNestedListsAndObjects, tcQuoted, tcEmptyList, tcHelloWorld]  tcEmptyList :: TestCase-tcEmptyList = +tcEmptyList =   TestCase     { tcName = "Empty root list"     , tcInput = "[]"@@ -57,6 +57,8 @@    "dateString": "2038-01-19",    "piString": "3.14",    "expString": "1e3",+   "leadingSpace" : " leading space",+   "leadingSymbol" : "!leading symbol",    "asteriskString": "*",    "multiLine": "The first line is followed by the\nsecond line\n",    "multiLineWithSpaces": "         This has extra\n     spaces at the beginning\n",@@ -67,12 +69,14 @@ |]     , tcOutput =         [s|asteriskString: "*"-boolString: "true"-dateString: "2038-01-19"+boolString: 'true'+dateString: '2038-01-19' emptyObject: {}-expString: "1e3"+expString: '1e3' isFalse: false isTrue: true+leadingSpace: " leading space"+leadingSymbol: "!leading symbol" list:   - foo   - bar@@ -86,8 +90,8 @@        spaces at the beginning notMultiline: "This won't be\nmulti-lined" nullValue: null-numberString: "12345"-piString: "3.14"+numberString: '12345'+piString: '3.14' "quoted ! key": true |]     , tcAlwaysQuote = False@@ -202,6 +206,39 @@ 'foo': 'bar' |]     , tcAlwaysQuote = True+    }++tcHelloWorld :: TestCase+tcHelloWorld =+  TestCase+    { tcName = "Hello World"+    , tcInput =+        [s|+{ "image": "node 10.15.3"+, "pipelines":+  { "default":+    [ { "step":+        { "caches": []+        , "name": "hello world"+        , "script": [ "echo hello" ]+        }+      }+    ]+    +  }+}+|]+    , tcOutput =+        [s|image: node 10.15.3+pipelines:+  default:+    - step:+        caches: []+        name: hello world+        script:+          - echo hello+|]+    , tcAlwaysQuote = False     }  foo :: Data.Aeson.Value