diff --git a/.gitignore b/.gitignore index 21e2b91..3467656 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /coverage /node_modules /npm-debug.log +/.vscode diff --git a/README.md b/README.md index 33df258..a68d92f 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,10 @@ The `options` object may contain the following: `=` character. By default, whitespace is omitted, to be friendly to some persnickety old parsers that don't tolerate it well. But some find that it's more human-readable and pretty with the whitespace. +* `ìsArray` Boolean to specify how arrays should be handled. By default an array + value will be suffixed with `[]`. If isArray is set to false multiple occurances + of the same key will be written underneath each other in the file + e.g. the way the _DNS_ setting is handled in [systemd networkd files](https://wiki.archlinux.org/index.php/Systemd-networkd). For backwards compatibility reasons, if a `string` options is passed in, then it is assumed to be the `section` value. diff --git a/ini.js b/ini.js index 590195d..872978c 100644 --- a/ini.js +++ b/ini.js @@ -5,8 +5,7 @@ exports.stringify = exports.encode = encode exports.safe = safe exports.unsafe = unsafe -var eol = typeof process !== 'undefined' && - process.platform === 'win32' ? '\r\n' : '\n' +var eol = require('os').EOL function encode (obj, opt) { var children = [] @@ -15,20 +14,25 @@ function encode (obj, opt) { if (typeof opt === 'string') { opt = { section: opt, - whitespace: false + whitespace: false, + isArray: true } } else { opt = opt || {} opt.whitespace = opt.whitespace === true + opt.isArray = opt.isArray === true } var separator = opt.whitespace ? ' = ' : '=' - Object.keys(obj).forEach(function (k, _, __) { var val = obj[k] if (val && Array.isArray(val)) { val.forEach(function (item) { - out += safe(k + '[]') + separator + safe(item) + '\n' + if (opt.isArray) { + out += safe(k + '[]') + separator + safe(item) + eol + } else { + out += safe(k) + separator + safe(item) + eol + } }) } else if (val && typeof val === 'object') { children.push(k) @@ -46,7 +50,8 @@ function encode (obj, opt) { var section = (opt.section ? opt.section + '.' : '') + nk var child = encode(obj[k], { section: section, - whitespace: opt.whitespace + whitespace: opt.whitespace, + isArray: opt.isArray }) if (out.length && child.length) { out += eol @@ -62,7 +67,7 @@ function dotSplit (str) { .replace(/\\\./g, '\u0001') .split(/\./).map(function (part) { return part.replace(/\1/g, '\\.') - .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001') + .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001') }) } @@ -73,7 +78,6 @@ function decode (str) { // section |key = value var re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i var lines = str.split(/[\r\n]+/g) - lines.forEach(function (line, _, __) { if (!line || line.match(/^\s*[;#]/)) return var match = line.match(re) @@ -92,13 +96,19 @@ function decode (str) { } // Convert keys with '[]' suffix to an array - if (key.length > 2 && key.slice(-2) === '[]') { + if ((key.length > 2 && key.slice(-2) === '[]')) { key = key.substring(0, key.length - 2) if (!p[key]) { p[key] = [] } else if (!Array.isArray(p[key])) { p[key] = [p[key]] } + } else if (p[key]) { + if (!Array.isArray(p[key])) { + p[key] = [p[key]] + } else { + p[key] = p[key] + } } // safeguard against resetting a previously defined @@ -150,10 +160,10 @@ function safe (val) { val.match(/[=\r\n]/) || val.match(/^\[/) || (val.length > 1 && - isQuoted(val)) || + isQuoted(val)) || val !== val.trim()) - ? JSON.stringify(val) - : val.replace(/;/g, '\\;').replace(/#/g, '\\#') + ? JSON.stringify(val) + : val.replace(/;/g, '\\;').replace(/#/g, '\\#') } function unsafe (val, doUnesc) { diff --git a/package-lock.json b/package-lock.json index c62cb53..20b8027 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,12 +51,12 @@ }, "ansi-regex": { "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", - "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "integrity": "sha512-jCcLjwL2jOaTcRIaJkoRteMwNXg8nfJvwT/9K91kwZhH7bf4lsprqZ2+Qa7tSp8BYtejobOCBkDreC07q0KmZw==", "dev": true }, "ansi-styles": { "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz", - "integrity": "sha1-mQ90cUaSe1Wakyv5KVkWPWDA0OI=", + "integrity": "sha512-qGfeDJjjwuLKKzFsdbYhnbn4Hqxkel6cSzdCP5IYmT38eIzVxGCzcOceJNkMG0sD5QMFz8SauI5Y+5lwcgHIgA==", "dev": true }, "argparse": { @@ -139,6 +139,29 @@ "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", "supports-color": "2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz", + "integrity": "sha512-Moms4LX81Yz8bfx4CR+r2LQodaAV0SSUHKacBi9bylry3/+ipQX9uOah6/zGXRfBR553xSf1wuOskE22/gAryw==", + "dev": true + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + } + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", + "integrity": "sha512-leU/wDjPxUZLHqEy4mYnNETRx1jAO1BJ6oTgn9PQWeAiO8kfng2LBq1iXYsN8UYPPRmAizc51nUY6w2Nv12Hog==", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + } + } } } } @@ -194,19 +217,19 @@ }, "chalk": { "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz", - "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=", + "integrity": "sha512-W10W+QfIxJlTm3VRtg8eafwUBkDfUPFvRvPv4jCD9vF4+HzlAyXJ7P3Y5yw/r+gJ1TzFEU6oFqMgp1dIVpYr0A==", "dev": true, "requires": { "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz", - "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" }, "dependencies": { "supports-color": { "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } @@ -262,11 +285,6 @@ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, - "concat-map": { - "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, "concat-stream": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", @@ -294,7 +312,7 @@ }, "core-util-is": { "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz", - "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg=", + "integrity": "sha512-fyj6blBb339ReZvm1g6NHGVI/q7THT6UJb1GVDMVxRvGb2v9J1xazqnfQ10wrChRH6tpxJLY/eUmFH0+gANIRA==", "dev": true }, "cross-spawn": { @@ -346,7 +364,7 @@ }, "debug": { "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "integrity": "sha512-X0rGvJcskG1c3TgSCPqHJ0XJgwlcvOC7elJ5Y0hYuKBZoVqWpAMfLOeIh2UI/DCQ5ruodIjvsugZtjUYUw2pUw==", "dev": true, "requires": { "ms": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" @@ -532,8 +550,9 @@ } }, "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz", - "integrity": "sha1-ni2LJbwlVcMzZyN1DgPwmcJzW7U=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "escope": { @@ -604,10 +623,36 @@ "dev": true, "requires": { "ansi-styles": "2.2.1", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz", - "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", "supports-color": "2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + } + } } }, "js-yaml": { @@ -1048,7 +1093,8 @@ } }, "has-ansi": { - "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { @@ -1069,7 +1115,7 @@ }, "inflight": { "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", - "integrity": "sha1-bLtFIevVHODsCpNr/XZX736bFyo=", + "integrity": "sha512-yMOGXregdgA+mer4gLyGWfj/gx0vzqmXtIY3YTxaQg4OZdk4GsrgiFCf/G96kVQt/aJDJyQPDeb/NtQRZp13xg==", "dev": true, "requires": { "once": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", @@ -1078,7 +1124,7 @@ }, "inherits": { "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==", "dev": true }, "inquirer": { @@ -1098,7 +1144,7 @@ "run-async": "0.1.0", "rx-lite": "3.1.2", "string-width": "1.0.2", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", + "strip-ansi": "3.0.1", "through": "2.3.8" }, "dependencies": { @@ -1419,6 +1465,13 @@ "requires": { "balanced-match": "1.0.0", "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + }, + "dependencies": { + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + } } } } @@ -1440,7 +1493,7 @@ }, "ms": { "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "integrity": "sha512-lRLiIR9fSNpnP6TC4v8+4OU7oStC01esuNowdQ34L+Gk8e5Puoc88IqJ+XAY/B3Mn2ZKis8l8HX90oU8ivzUHg==", "dev": true }, "mute-stream": { @@ -1486,7 +1539,7 @@ }, "once": { "version": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", - "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "integrity": "sha512-tPQxpk4nBjTgu+eHijWhgX2d+tE6HQyMPVnzY5b1qenTUFsxBaKlzEFUF+XVfbToFuVFm8hX+PzV9u3PewDZ4Q==", "dev": true, "requires": { "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" @@ -1570,7 +1623,7 @@ }, "path-is-absolute": { "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", - "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "integrity": "sha512-hUUTsB/vByumPhn43R+Azhsx4TQPvyQqW+XyCR6UA8ae+FGIjf5Oygj6o/FYK4ZdwnrXth2eIBKk4YlrUU0ElQ==", "dev": true }, "path-is-inside": { @@ -1847,7 +1900,7 @@ }, "sprintf-js": { "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "sshpk": { @@ -1931,7 +1984,7 @@ "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz" + "strip-ansi": "3.0.1" } }, "string_decoder": { @@ -1949,8 +2002,9 @@ "dev": true }, "strip-ansi": { - "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", - "integrity": "sha1-dRC2ZVZ8qRTMtdfgcnY6yWi+NyQ=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" @@ -3971,7 +4025,7 @@ "color-support": "1.1.3", "debug": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "diff": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz", + "escape-string-regexp": "1.0.5", "glob": "7.1.2", "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.2.tgz", "readable-stream": "2.3.3", @@ -3983,29 +4037,25 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, - "optional": true, "requires": { "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz", "inherits": "2.0.3", @@ -4021,7 +4071,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, - "optional": true, "requires": { "safe-buffer": "5.1.1" } @@ -4129,7 +4178,7 @@ }, "util-deprecate": { "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz", - "integrity": "sha1-NVaj0TxMaqeYPX4kJUeBlxmbeIE=", + "integrity": "sha512-/f+A7C3gucLtZ6F6z33sFBFxIrry4KPiO4S1r9KrwNv6ABp/T+IHJzzYGRFCzs2RfgTIm8cA3TJuTdc8INlkNQ==", "dev": true }, "verror": { @@ -4165,7 +4214,7 @@ }, "wrappy": { "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", - "integrity": "sha1-HmWWmWXMvC20VIxrhKbyxa7dRzk=", + "integrity": "sha512-42h1d25nW6G/N7l16Oz4vqCOLIFobFBOwZrBYlCxJ/QuS2o1Gdn1PzSoiYndbnL9rgGIGZ6Qn09AIpyhrkepfw==", "dev": true }, "write": { diff --git a/test/fixtures/foo.ini b/test/fixtures/foo.ini index fc2080f..7f27c3d 100644 --- a/test/fixtures/foo.ini +++ b/test/fixtures/foo.ini @@ -25,7 +25,7 @@ ar[] = three ; This should be included in the array ar = this is included -; Test resetting of a value (and not turn it into an array) +; Turn this into an array br = cold br = warm diff --git a/test/foo.js b/test/foo.js index 58102d1..ecf4ac7 100644 --- a/test/foo.js +++ b/test/foo.js @@ -2,56 +2,142 @@ var i = require("../") , tap = require("tap") , test = tap.test , fs = require("fs") + , eol = require('os').EOL , path = require("path") , fixture = path.resolve(__dirname, "./fixtures/foo.ini") , data = fs.readFileSync(fixture, "utf8") , d - , expectE = 'o=p\n' - + 'a with spaces=b c\n' - + '" xa n p "="\\"\\r\\nyoyoyo\\r\\r\\n"\n' - + '"[disturbing]"=hey you never know\n' - + 's=something\n' - + 's1=\"something\'\n' - + 's2=something else\n' - + 'zr[]=deedee\n' - + 'ar[]=one\n' - + 'ar[]=three\n' - + 'ar[]=this is included\n' - + 'br=warm\n' - + 'eq=\"eq=eq\"\n' - + '\n' - + '[a]\n' - + 'av=a val\n' - + 'e={ o: p, a: ' - + '{ av: a val, b: { c: { e: "this [value]" ' - + '} } } }\nj="\\"{ o: \\"p\\", a: { av:' - + ' \\"a val\\", b: { c: { e: \\"this [value]' - + '\\" } } } }\\""\n"[]"=a square?\n' - + 'cr[]=four\ncr[]=eight\n\n' - +'[a.b.c]\ne=1\n' - + 'j=2\n\n[x\\.y\\.z]\nx.y.z=xyz\n\n' - + '[x\\.y\\.z.a\\.b\\.c]\na.b.c=abc\n' - + 'nocomment=this\\; this is not a comment\n' - + 'noHashComment=this\\# this is not a comment\n' + , expectIisArray = 'o=p'+eol + + 'a with spaces=b c'+eol + + '" xa n p "="\\"\\r\\nyoyoyo\\r\\r\\n"'+eol + + '"[disturbing]"=hey you never know'+eol + + 's=something'+eol + + 's1=\"something\''+eol + + 's2=something else'+eol + + 'zr=deedee'+eol + + 'ar=one'+eol + + 'ar=three'+eol + + 'ar=this is included'+eol + + 'br=warm'+eol + + 'eq=\"eq=eq\"'+eol + + ''+eol + + '[a]'+eol + + 'av=a val'+eol + + 'e={ o: p, a: ' + + '{ av: a val, b: { c: { e: "this [value]" ' + + '} } } }'+eol+'j="\\"{ o: \\"p\\", a: { av:' + + ' \\"a val\\", b: { c: { e: \\"this [value]' + + '\\" } } } }\\""'+eol+'"[]"=a square?'+eol + + 'cr=four'+eol+'cr=eight'+eol+eol + + '[a.b.c]'+eol + + 'e=1'+eol + + 'j=2'+eol+eol + + '[x\\.y\\.z]'+eol + + 'x.y.z=xyz'+eol+eol + + '[x\\.y\\.z.a\\.b\\.c]'+eol + + 'a.b.c=abc'+eol + + 'nocomment=this\\; this is not a comment'+eol + + 'noHashComment=this\\# this is not a comment'+eol + , expectI = 'o=p'+eol + + 'a with spaces=b c'+eol + + '" xa n p "="\\"\\r\\nyoyoyo\\r\\r\\n"'+eol + + '"[disturbing]"=hey you never know'+eol + + 's=something'+eol + + 's1=\"something\''+eol + + 's2=something else'+eol + + 'zr[]=deedee'+eol + + 'ar[]=one'+eol + + 'ar[]=three'+eol + + 'ar[]=this is included'+eol + + 'br=warm'+eol + + 'eq=\"eq=eq\"'+eol + + ''+eol + + '[a]'+eol + + 'av=a val'+eol + + 'e={ o: p, a: ' + + '{ av: a val, b: { c: { e: "this [value]" ' + + '} } } }'+eol+'j="\\"{ o: \\"p\\", a: { av:' + + ' \\"a val\\", b: { c: { e: \\"this [value]' + + '\\" } } } }\\""'+eol+'"[]"=a square?'+eol + + 'cr[]=four'+eol+'cr[]=eight'+eol+eol + + '[a.b.c]'+eol + + 'e=1'+eol + + 'j=2'+eol+eol + + '[x\\.y\\.z]'+eol + + 'x.y.z=xyz'+eol+eol + + '[x\\.y\\.z.a\\.b\\.c]'+eol + + 'a.b.c=abc'+eol + + 'nocomment=this\\; this is not a comment'+eol + + 'noHashComment=this\\# this is not a comment'+eol + , expectE = 'o=p'+eol + + 'a with spaces=b c'+eol + + '" xa n p "="\\"\\r\\nyoyoyo\\r\\r\\n"'+eol + + '"[disturbing]"=hey you never know'+eol + + 's=something'+eol + + 's1=\"something\''+eol + + 's2=something else'+eol + + 'zr[]=deedee'+eol + + 'ar[]=one'+eol + + 'ar[]=three'+eol + + 'ar[]=this is included'+eol + + 'br=warm'+eol + + 'eq=\"eq=eq\"'+eol + + ''+eol + + '[a]'+eol + + 'av=a val'+eol + + 'e={ o: p, a: ' + + '{ av: a val, b: { c: { e: "this [value]" ' + + '} } } }'+eol+'j="\\"{ o: \\"p\\", a: { av:' + + ' \\"a val\\", b: { c: { e: \\"this [value]' + + '\\" } } } }\\""'+eol+'"[]"=a square?'+eol + + 'cr[]=four'+eol+'cr[]=eight'+eol+eol + + '[a.b.c]'+eol + + 'e=1'+eol + + 'j=2'+eol+eol + + '[x\\.y\\.z]'+eol + + 'x.y.z=xyz'+eol+eol + + '[x\\.y\\.z.a\\.b\\.c]'+eol + + 'a.b.c=abc'+eol + + 'nocomment=this\\; this is not a comment'+eol + + 'noHashComment=this\\# this is not a comment'+eol + , expectH = '[Match]'+eol + +'Name=eth0'+eol+eol + +'[Network]'+eol + +'DHCP=no'+eol + +'Address=192.168.1.75/24'+eol + +'Gateway=192.168.1.1'+eol + +'DNS=8.8.8.8'+eol + +'DNS=8.8.4.4'+eol + , expectHisArray = '[Match]'+eol + +'Name=eth0'+eol+eol + +'[Network]'+eol + +'DHCP=no'+eol + +'Address=192.168.1.75/24'+eol + +'Gateway=192.168.1.1'+eol + +'DNS[]=8.8.8.8'+eol + +'DNS[]=8.8.4.4'+eol , expectD = - { o: 'p', + { + o: 'p', 'a with spaces': 'b c', - " xa n p ":'"\r\nyoyoyo\r\r\n', + " xa n p ": '"\r\nyoyoyo\r\r\n', '[disturbing]': 'hey you never know', 's': 'something', - 's1' : '\"something\'', + 's1': '\"something\'', 's2': 'something else', 'zr': ['deedee'], 'ar': ['one', 'three', 'this is included'], - 'br': 'warm', + 'br': ['cold', 'warm'], 'eq': 'eq=eq', a: - { av: 'a val', - e: '{ o: p, a: { av: a val, b: { c: { e: "this [value]" } } } }', - j: '"{ o: "p", a: { av: "a val", b: { c: { e: "this [value]" } } } }"', - "[]": "a square?", - cr: ['four', 'eight'], - b: { c: { e: '1', j: '2' } } }, + { + av: 'a val', + e: '{ o: p, a: { av: a val, b: { c: { e: "this [value]" } } } }', + j: '"{ o: "p", a: { av: "a val", b: { c: { e: "this [value]" } } } }"', + "[]": "a square?", + cr: ['four', 'eight'], + b: { c: { e: '1', j: '2' } } + }, 'x.y.z': { 'x.y.z': 'xyz', 'a.b.c': { @@ -61,16 +147,16 @@ var i = require("../") } } } - , expectF = '[prefix.log]\n' - + 'type=file\n\n' - + '[prefix.log.level]\n' - + 'label=debug\n' - + 'value=10\n' - , expectG = '[log]\n' - + 'type = file\n\n' - + '[log.level]\n' - + 'label = debug\n' - + 'value = 10\n' + , expectF = '[prefix.log]'+eol + + 'type=file'+eol+eol + + '[prefix.log.level]'+eol + + 'label=debug'+eol + + 'value=10'+eol + , expectG = '[log]' +eol + + 'type = file'+eol+eol + + '[log.level]'+eol + + 'label = debug'+eol + + 'value = 10'+eol test("decode from file", function (t) { var d = i.decode(data) @@ -78,14 +164,50 @@ test("decode from file", function (t) { t.end() }) -test("encode from data", function (t) { - var e = i.encode(expectD) +test("encode from data. isArray=true", function (t) { + var e = i.encode(i.decode(expectE), { isArray: true }) t.deepEqual(e, expectE) - var obj = {log: { type:'file', level: {label:'debug', value:10} } } + var obj = { log: { type: 'file', level: { label: 'debug', value: 10 } } } + e = i.encode(obj) + t.notEqual(e.slice(0, 1), eol, 'Never a blank first line') + t.notEqual(e.slice(-2), eol+eol, 'Never a blank final line') + + t.end() +}) + +test("encode from data. isArray=false", function (t) { + var e = i.encode(i.decode(expectI), { isArray: false }) + t.deepEqual(e, expectIisArray) + + var obj = { log: { type: 'file', level: { label: 'debug', value: 10 } } } + e = i.encode(obj) + t.notEqual(e.slice(0, 1), eol, 'Never a blank first line') + t.notEqual(e.slice(-2), eol+eol, 'Never a blank final line') + + t.end() +}) + +test("encode systemd network configuration. isArray=false", function (t) { + var e = i.encode(i.decode(expectH), { isArray: false }) + t.deepEqual(e, expectH) + + var obj = { log: { type: 'file', level: { label: 'debug', value: 10 } } } e = i.encode(obj) - t.notEqual(e.slice(0, 1), '\n', 'Never a blank first line') - t.notEqual(e.slice(-2), '\n\n', 'Never a blank final line') + t.notEqual(e.slice(0, 1), eol, 'Never a blank first line') + t.notEqual(e.slice(-2), eol+eol, 'Never a blank final line') + + t.end() +}) + +test("encode systemd network configuration. isArray=true", function (t) { + var e = i.encode(i.decode(expectH), { isArray: true }) + t.deepEqual(e, expectHisArray) + + var obj = { log: { type: 'file', level: { label: 'debug', value: 10 } } } + e = i.encode(obj) + t.notEqual(e.slice(0, 1), eol, 'Never a blank first line') + t.notEqual(e.slice(-2), eol+eol, 'Never a blank final line') t.end() }) @@ -93,15 +215,13 @@ test("encode from data", function (t) { test("encode with option", function (t) { var obj = {log: { type:'file', level: {label:'debug', value:10} } } e = i.encode(obj, {section: 'prefix'}) - t.equal(e, expectF) t.end() }) test("encode with whitespace", function (t) { - var obj = {log: { type:'file', level: {label:'debug', value:10} } } - e = i.encode(obj, {whitespace: true}) - + var obj = { log: { type: 'file', level: { label: 'debug', value: 10 } } } + e = i.encode(obj, { whitespace: true }) t.equal(e, expectG) t.end() }) diff --git a/test/win32.js b/test/win32.js index 3ae71fe..4573e24 100644 --- a/test/win32.js +++ b/test/win32.js @@ -1,16 +1,17 @@ -var t = require('tap') +var t = require('tap'), + eol = require('os').EOL Object.defineProperty(process, 'platform', { value: 'win32' }) const ini = require('../ini.js') -const res = ini.encode({foo: { bar: 'baz' }}) -t.equal(res, "[foo]\r\nbar=baz\r\n") +const res = ini.encode({ foo: { bar: 'baz' } }) +t.equal(res, "[foo]"+eol+"bar=baz"+eol) -t.equal(ini.encode({bar: 'baz'}, 'foo'), '[foo]\r\nbar=baz\r\n') +t.equal(ini.encode({ bar: 'baz' }, 'foo'), '[foo]'+eol+'bar=baz'+eol) -t.same(ini.decode('=just junk!\r\n[foo]\r\nbar\r\n'), - { foo: { bar: true }}) +t.same(ini.decode('=just junk!'+eol+'[foo]'+eol+'bar'+eol), + { foo: { bar: true } }) -t.same(ini.decode('[x]\r\ny=1\r\ny[]=2\r\n'), { +t.same(ini.decode('[x]'+eol+'y=1'+eol+'y[]=2'+eol), { x: { y: [1, 2] }