Comparing version 1.3.8 to 2.0.0
176
ini.js
@@ -1,14 +0,9 @@ | ||
exports.parse = exports.decode = decode | ||
const { hasOwnProperty } = Object.prototype | ||
exports.stringify = exports.encode = encode | ||
exports.safe = safe | ||
exports.unsafe = unsafe | ||
var eol = typeof process !== 'undefined' && | ||
const eol = typeof process !== 'undefined' && | ||
process.platform === 'win32' ? '\r\n' : '\n' | ||
function encode (obj, opt) { | ||
var children = [] | ||
var out = '' | ||
const encode = (obj, opt) => { | ||
const children = [] | ||
let out = '' | ||
@@ -21,14 +16,13 @@ if (typeof opt === 'string') { | ||
} else { | ||
opt = opt || {} | ||
opt = opt || Object.create(null) | ||
opt.whitespace = opt.whitespace === true | ||
} | ||
var separator = opt.whitespace ? ' = ' : '=' | ||
const separator = opt.whitespace ? ' = ' : '=' | ||
Object.keys(obj).forEach(function (k, _, __) { | ||
var val = obj[k] | ||
for (const k of Object.keys(obj)) { | ||
const val = obj[k] | ||
if (val && Array.isArray(val)) { | ||
val.forEach(function (item) { | ||
for (const item of val) | ||
out += safe(k + '[]') + separator + safe(item) + '\n' | ||
}) | ||
} else if (val && typeof val === 'object') | ||
@@ -38,3 +32,3 @@ children.push(k) | ||
out += safe(k) + separator + safe(val) + eol | ||
}) | ||
} | ||
@@ -44,8 +38,9 @@ if (opt.section && out.length) | ||
children.forEach(function (k, _, __) { | ||
var nk = dotSplit(k).join('\\.') | ||
var section = (opt.section ? opt.section + '.' : '') + nk | ||
var child = encode(obj[k], { | ||
section: section, | ||
whitespace: opt.whitespace, | ||
for (const k of children) { | ||
const nk = dotSplit(k).join('\\.') | ||
const section = (opt.section ? opt.section + '.' : '') + nk | ||
const { whitespace } = opt | ||
const child = encode(obj[k], { | ||
section, | ||
whitespace, | ||
}) | ||
@@ -56,3 +51,3 @@ if (out.length && child.length) | ||
out += child | ||
}) | ||
} | ||
@@ -62,25 +57,24 @@ return out | ||
function dotSplit (str) { | ||
return str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002') | ||
const dotSplit = str => | ||
str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002') | ||
.replace(/\\\./g, '\u0001') | ||
.split(/\./).map(function (part) { | ||
return part.replace(/\1/g, '\\.') | ||
.replace(/\2LITERAL\\1LITERAL\2/g, '\u0001') | ||
}) | ||
} | ||
.split(/\./) | ||
.map(part => | ||
part.replace(/\1/g, '\\.') | ||
.replace(/\2LITERAL\\1LITERAL\2/g, '\u0001')) | ||
function decode (str) { | ||
var out = {} | ||
var p = out | ||
var section = null | ||
const decode = str => { | ||
const out = Object.create(null) | ||
let p = out | ||
let section = null | ||
// section |key = value | ||
var re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i | ||
var lines = str.split(/[\r\n]+/g) | ||
const re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i | ||
const lines = str.split(/[\r\n]+/g) | ||
lines.forEach(function (line, _, __) { | ||
for (const line of lines) { | ||
if (!line || line.match(/^\s*[;#]/)) | ||
return | ||
var match = line.match(re) | ||
continue | ||
const match = line.match(re) | ||
if (!match) | ||
return | ||
continue | ||
if (match[1] !== undefined) { | ||
@@ -91,24 +85,22 @@ section = unsafe(match[1]) | ||
// keep parsing the section, but don't attach it. | ||
p = {} | ||
return | ||
p = Object.create(null) | ||
continue | ||
} | ||
p = out[section] = out[section] || {} | ||
return | ||
p = out[section] = out[section] || Object.create(null) | ||
continue | ||
} | ||
var key = unsafe(match[2]) | ||
const keyRaw = unsafe(match[2]) | ||
const isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]' | ||
const key = isArray ? keyRaw.slice(0, -2) : keyRaw | ||
if (key === '__proto__') | ||
return | ||
var value = match[3] ? unsafe(match[4]) : true | ||
switch (value) { | ||
case 'true': | ||
case 'false': | ||
case 'null': value = JSON.parse(value) | ||
} | ||
continue | ||
const valueRaw = match[3] ? unsafe(match[4]) : true | ||
const value = valueRaw === 'true' || | ||
valueRaw === 'false' || | ||
valueRaw === 'null' ? JSON.parse(valueRaw) | ||
: valueRaw | ||
// Convert keys with '[]' suffix to an array | ||
if (key.length > 2 && key.slice(-2) === '[]') { | ||
key = key.substring(0, key.length - 2) | ||
if (key === '__proto__') | ||
return | ||
if (!p[key]) | ||
if (isArray) { | ||
if (!hasOwnProperty.call(p, key)) | ||
p[key] = [] | ||
@@ -125,33 +117,34 @@ else if (!Array.isArray(p[key])) | ||
p[key] = value | ||
}) | ||
} | ||
// {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}} | ||
// use a filter to return the keys that have to be deleted. | ||
Object.keys(out).filter(function (k, _, __) { | ||
if (!out[k] || | ||
typeof out[k] !== 'object' || | ||
Array.isArray(out[k])) | ||
return false | ||
const remove = [] | ||
for (const k of Object.keys(out)) { | ||
if (!hasOwnProperty.call(out, k) || | ||
typeof out[k] !== 'object' || | ||
Array.isArray(out[k])) | ||
continue | ||
// see if the parent section is also an object. | ||
// if so, add it to that, and mark this one for deletion | ||
var parts = dotSplit(k) | ||
var p = out | ||
var l = parts.pop() | ||
var nl = l.replace(/\\\./g, '.') | ||
parts.forEach(function (part, _, __) { | ||
const parts = dotSplit(k) | ||
let p = out | ||
const l = parts.pop() | ||
const nl = l.replace(/\\\./g, '.') | ||
for (const part of parts) { | ||
if (part === '__proto__') | ||
return | ||
if (!p[part] || typeof p[part] !== 'object') | ||
p[part] = {} | ||
continue | ||
if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') | ||
p[part] = Object.create(null) | ||
p = p[part] | ||
}) | ||
} | ||
if (p === out && nl === l) | ||
return false | ||
continue | ||
p[nl] = out[k] | ||
return true | ||
}).forEach(function (del, _, __) { | ||
remove.push(k) | ||
} | ||
for (const del of remove) | ||
delete out[del] | ||
}) | ||
@@ -161,9 +154,8 @@ return out | ||
function isQuoted (val) { | ||
return (val.charAt(0) === '"' && val.slice(-1) === '"') || | ||
const isQuoted = val => | ||
(val.charAt(0) === '"' && val.slice(-1) === '"') || | ||
(val.charAt(0) === "'" && val.slice(-1) === "'") | ||
} | ||
function safe (val) { | ||
return (typeof val !== 'string' || | ||
const safe = val => | ||
(typeof val !== 'string' || | ||
val.match(/[=\r\n]/) || | ||
@@ -176,5 +168,4 @@ val.match(/^\[/) || | ||
: val.replace(/;/g, '\\;').replace(/#/g, '\\#') | ||
} | ||
function unsafe (val, doUnesc) { | ||
const unsafe = (val, doUnesc) => { | ||
val = (val || '').trim() | ||
@@ -191,6 +182,6 @@ if (isQuoted(val)) { | ||
// walk the val to find the first not-escaped ; character | ||
var esc = false | ||
var unesc = '' | ||
for (var i = 0, l = val.length; i < l; i++) { | ||
var c = val.charAt(i) | ||
let esc = false | ||
let unesc = '' | ||
for (let i = 0, l = val.length; i < l; i++) { | ||
const c = val.charAt(i) | ||
if (esc) { | ||
@@ -217,1 +208,10 @@ if ('\\;#'.indexOf(c) !== -1) | ||
} | ||
module.exports = { | ||
parse: decode, | ||
decode, | ||
stringify: encode, | ||
encode, | ||
safe, | ||
unsafe, | ||
} |
@@ -5,3 +5,3 @@ { | ||
"description": "An ini encoder/decoder for node", | ||
"version": "1.3.8", | ||
"version": "2.0.0", | ||
"repository": { | ||
@@ -33,3 +33,6 @@ "type": "git", | ||
"ini.js" | ||
] | ||
], | ||
"engines": { | ||
"node": ">=10" | ||
} | ||
} |
9474
181