@nodecraft/ini
Advanced tools
Comparing version 2.1.1 to 2.1.2
145
ini.js
'use strict'; | ||
/* eslint-disable no-use-before-define */ | ||
exports.parse = exports.decode = decode; | ||
const {hasOwnProperty} = Object.prototype; | ||
exports.stringify = exports.encode = encode; | ||
exports.safe = safe; | ||
exports.unsafe = unsafe; | ||
const eol = require('os').EOL; | ||
function encode(obj, opt){ | ||
const encode = (obj, opt) => { | ||
const children = []; | ||
@@ -31,3 +26,3 @@ let out = ''; | ||
if(val && Array.isArray(val)){ | ||
val.forEach(function(item){ | ||
for(const item of val){ | ||
if(opt.inlineArrays){ | ||
@@ -39,3 +34,3 @@ out += safe(key) + separator + safe(item) + eol; | ||
} | ||
}); | ||
} | ||
}else if(val && typeof val === 'object'){ | ||
@@ -48,7 +43,7 @@ children.push(key); | ||
if(opt.section && out.length){ | ||
if(opt.section && out.length > 0){ | ||
out = '[' + safe(opt.section) + ']' + eol + out; | ||
} | ||
children.forEach(function(key){ | ||
for(const key of children){ | ||
const parsedSection = dotSplit(key).join('\\.'); | ||
@@ -61,21 +56,18 @@ const section = (opt.section ? opt.section + '.' : '') + parsedSection; | ||
}); | ||
if(out.length && child.length){ | ||
if(out.length > 0 && child.length > 0){ | ||
out += eol; | ||
} | ||
out += child; | ||
}); | ||
} | ||
return out; | ||
} | ||
}; | ||
function dotSplit(str){ | ||
return 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'); | ||
}); | ||
} | ||
const dotSplit = str => str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002') | ||
.replace(/\\\./g, '\u0001') | ||
.split(/\./) | ||
.map(part => part.replace(/\1/g, '\\.') | ||
.replace(/\2LITERAL\\1LITERAL\2/g, '\u0001')); | ||
function decode(str, opt = {}){ | ||
const decode = (str, opt = {}) => { | ||
const defaultValue = typeof opt.defaultValue !== 'undefined' ? opt.defaultValue : ''; | ||
@@ -87,9 +79,9 @@ | ||
// section |key = value | ||
const re = /^\[([^\]]*)\]$|^([^=]+)(?:=(.*))?$/i; | ||
const lines = str.split(/[\r\n]+/g); | ||
const commentMatch = /^\s*[;#]/; | ||
lines.forEach(function(line){ | ||
if(!line || line.match(commentMatch)){ return; } | ||
const re = /^\[([^\]]*)]$|^([^=]+)(?:=(.*))?$/i; | ||
const lines = str.split(/[\n\r]+/g); | ||
const commentMatch = /^\s*[#;]/; | ||
for(const line of lines){ | ||
if(!line || commentMatch.test(line)){ continue; } | ||
const match = line.match(re); | ||
if(!match){ return; } | ||
if(!match){ continue; } | ||
if(match[1] !== undefined){ | ||
@@ -101,9 +93,9 @@ section = unsafe(match[1]); | ||
ref = Object.create(null); | ||
return; | ||
continue; | ||
} | ||
ref = out[section] = out[section] || Object.create(null); | ||
return; | ||
continue; | ||
} | ||
let key = unsafe(match[2]); | ||
if(key === '__proto__'){ return; } | ||
if(key === '__proto__'){ continue; } | ||
let value = match[3] ? unsafe(match[3]) : defaultValue; | ||
@@ -122,5 +114,5 @@ switch(value){ | ||
if(key.length > 2 && key.slice(-2) === '[]'){ | ||
key = key.substring(0, key.length - 2); | ||
if(key === '__proto__'){ return; } | ||
if(!ref[key]){ | ||
key = key.slice(0, Math.max(0, key.length - 2)); | ||
if(key === '__proto__'){ continue; } | ||
if(!hasOwnProperty.call(ref, key)){ | ||
ref[key] = []; | ||
@@ -141,9 +133,10 @@ }else if(!Array.isArray(ref[key])){ | ||
} | ||
}); | ||
} | ||
// {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(key){ | ||
if(!out[key] || typeof out[key] !== 'object' || Array.isArray(out[key])){ | ||
return false; | ||
const remove = []; | ||
for(const key of Object.keys(out)){ | ||
if(!hasOwnProperty.call(out, key) || typeof out[key] !== 'object' || Array.isArray(out[key])){ | ||
continue; | ||
} | ||
@@ -153,33 +146,34 @@ // see if the parent section is also an object. | ||
const parts = dotSplit(key); | ||
let p = out; | ||
let outPart = out; | ||
console.log('parts', parts); | ||
const lastKey = parts.pop(); | ||
const unescapedLastKey = lastKey.replace(/\\\./g, '.'); | ||
parts.forEach(function(part){ | ||
if(part === '__proto__'){ return; } | ||
if(!p[part] || typeof p[part] !== 'object'){ | ||
p[part] = Object.create(null); | ||
for(const part of parts){ | ||
if(part === '__proto__'){ continue; } | ||
if(!hasOwnProperty.call(outPart, part) || typeof outPart[part] !== 'object'){ | ||
outPart[part] = Object.create(null); | ||
} | ||
p = p[part]; | ||
}); | ||
if(p === out && unescapedLastKey === lastKey){ | ||
return false; | ||
outPart = outPart[part]; | ||
} | ||
p[unescapedLastKey] = out[key]; | ||
return true; | ||
}).forEach(function(del){ | ||
if(outPart === out && unescapedLastKey === lastKey){ | ||
continue; | ||
} | ||
outPart[unescapedLastKey] = out[key]; | ||
remove.push(key); | ||
} | ||
for(const del of remove){ | ||
delete out[del]; | ||
}); | ||
} | ||
return out; | ||
} | ||
}; | ||
// determines if string is encased in quotes | ||
function isQuoted(val){ | ||
return (val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'")); | ||
} | ||
const isQuoted = val => (val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'")); | ||
// escapes the string val such that it is safe to be used as a key or value in an ini-file. Basically escapes quotes | ||
function safe(val){ | ||
const safe = (val) => { | ||
// all kinds of values and keys | ||
if(typeof val !== 'string' || val.match(/[=\r\n]/) || val.match(/^\[/) || (val.length > 1 && isQuoted(val)) || val !== val.trim()){ | ||
if(typeof val !== 'string' || /[\n\r=]/.test(val) || /^\[/.test(val) || (val.length > 1 && isQuoted(val)) || val !== val.trim()){ | ||
return JSON.stringify(val); | ||
@@ -189,6 +183,6 @@ } | ||
return val.replace(/;/g, '\\;').replace(/#/g, '\\#'); | ||
} | ||
}; | ||
// unescapes the string val | ||
function unsafe(val){ | ||
const unsafe = (val) => { | ||
const escapableChars = '\\;#'; | ||
@@ -201,7 +195,7 @@ const commentChars = ';#'; | ||
if(val.charAt(0) === "'"){ | ||
val = val.substr(1, val.length - 2); | ||
val = val.substr(1, val.length - 2); // eslint-disable-line unicorn/prefer-string-slice | ||
} | ||
try{ | ||
val = JSON.parse(val); | ||
}catch(e){ | ||
}catch{ | ||
// we tried :( | ||
@@ -214,18 +208,18 @@ } | ||
let escapedVal = ''; | ||
for(let i = 0, l = val.length; i < l; i++){ | ||
const c = val.charAt(i); | ||
for(let i = 0, len = val.length; i < len; i++){ | ||
const char = val.charAt(i); | ||
if(isEscaping){ | ||
// check if this character is an escapable character like \ or ; or # | ||
if(escapableChars.indexOf(c) !== -1){ | ||
escapedVal += c; | ||
if(escapableChars.includes(char)){ | ||
escapedVal += char; | ||
}else{ | ||
escapedVal += '\\' + c; | ||
escapedVal += '\\' + char; | ||
} | ||
isEscaping = false; | ||
}else if(commentChars.indexOf(c) !== -1){ | ||
}else if(commentChars.includes(char)){ | ||
break; | ||
}else if(c === '\\'){ | ||
}else if(char === '\\'){ | ||
isEscaping = true; | ||
}else{ | ||
escapedVal += c; | ||
escapedVal += char; | ||
} | ||
@@ -238,2 +232,11 @@ } | ||
return escapedVal.trim(); | ||
} | ||
}; | ||
module.exports = { | ||
parse: decode, | ||
decode, | ||
stringify: encode, | ||
encode, | ||
safe, | ||
unsafe | ||
}; |
{ | ||
"name": "@nodecraft/ini", | ||
"version": "2.1.1", | ||
"version": "2.1.2", | ||
"description": "An ini encoder/decoder for node", | ||
@@ -24,12 +24,13 @@ "repository": { | ||
"devDependencies": { | ||
"eslint": "^7.15.0", | ||
"eslint-config-nodecraft": "^6.2.0", | ||
"eslint": "^7.18.0", | ||
"eslint-config-nodecraft": "^7.2.0", | ||
"eslint-plugin-json": "^2.1.2", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-unicorn": "^26.0.1", | ||
"tap": "^14" | ||
}, | ||
"engines": { | ||
"node": ">=8.11.1", | ||
"npm": ">=5.10.0" | ||
"node": ">=12.20.0", | ||
"npm": ">=6.14.9" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12396
208
6