JAVASCRIPT 383
Ini.js Guest on 17th April 2021 01:13:30 PM
  1.  
  2. exports.parse = exports.decode = decode
  3. exports.stringify = exports.encode = encode
  4.  
  5. exports.safe = safe
  6. exports.unsafe = unsafe
  7.  
  8. var eol = process.platform === "win32" ? "\r\n" : "\n"
  9.  
  10. function encode (obj, opt) {
  11.   var children = []
  12.     , out = ""
  13.  
  14.   if (typeof opt === "string") {
  15.     opt = {
  16.       section: opt,
  17.       whitespace: false
  18.     }
  19.   } else {
  20.     opt = opt || {}
  21.     opt.whitespace = opt.whitespace === true
  22.   }
  23.  
  24.   var separator = opt.whitespace ? " = " : "="
  25.  
  26.   Object.keys(obj).forEach(function (k, _, __) {
  27.     var val = obj[k]
  28.     if (val && Array.isArray(val)) {
  29.         val.forEach(function(item) {
  30.             out += safe(k + "[]") + separator + safe(item) + "\n"
  31.         })
  32.     }
  33.     else if (val && typeof val === "object") {
  34.       children.push(k)
  35.     } else {
  36.       out += safe(k) + separator + safe(val) + eol
  37.     }
  38.   })
  39.  
  40.   if (opt.section && out.length) {
  41.     out = "[" + safe(opt.section) + "]" + eol + out
  42.   }
  43.  
  44.   children.forEach(function (k, _, __) {
  45.     var nk = dotSplit(k).join('\\.')
  46.     var section = (opt.section ? opt.section + "." : "") + nk
  47.     var child = encode(obj[k], {
  48.       section: section,
  49.       whitespace: opt.whitespace
  50.     })
  51.     if (out.length && child.length) {
  52.       out += eol
  53.     }
  54.     out += child
  55.   })
  56.  
  57.   return out
  58. }
  59.  
  60. function dotSplit (str) {
  61.   return str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002')
  62.          .replace(/\\\./g, '\u0001')
  63.          .split(/\./).map(function (part) {
  64.            return part.replace(/\1/g, '\\.')
  65.                   .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001')
  66.         })
  67. }
  68.  
  69. function decode (str) {
  70.   var out = {}
  71.     , p = out
  72.     , section = null
  73.     , state = "START"
  74.            // section     |key = value
  75.     , re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i
  76.     , lines = str.split(/[\r\n]+/g)
  77.     , section = null
  78.  
  79.   lines.forEach(function (line, _, __) {
  80.     if (!line || line.match(/^\s*[;#]/)) return
  81.     var match = line.match(re)
  82.     if (!match) return
  83.     if (match[1] !== undefined) {
  84.       section = unsafe(match[1])
  85.       p = out[section] = out[section] || {}
  86.       return
  87.     }
  88.     var key = unsafe(match[2])
  89.       , value = match[3] ? unsafe((match[4] || "")) : true
  90.     switch (value) {
  91.       case 'true':
  92.       case 'false':
  93.       case 'null': value = JSON.parse(value)
  94.     }
  95.  
  96.     // Convert keys with '[]' suffix to an array
  97.     if (key.length > 2 && key.slice(-2) === "[]") {
  98.         key = key.substring(0, key.length - 2)
  99.         if (!p[key]) {
  100.           p[key] = []
  101.         }
  102.         else if (!Array.isArray(p[key])) {
  103.           p[key] = [p[key]]
  104.         }
  105.     }
  106.  
  107.     // safeguard against resetting a previously defined
  108.     // array by accidentally forgetting the brackets
  109.     if (Array.isArray(p[key])) {
  110.       p[key].push(value)
  111.     }
  112.     else {
  113.       p[key] = value
  114.     }
  115.   })
  116.  
  117.   // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
  118.   // use a filter to return the keys that have to be deleted.
  119.   Object.keys(out).filter(function (k, _, __) {
  120.     if (!out[k] || typeof out[k] !== "object" || Array.isArray(out[k])) return false
  121.     // see if the parent section is also an object.
  122.     // if so, add it to that, and mark this one for deletion
  123.     var parts = dotSplit(k)
  124.       , p = out
  125.       , l = parts.pop()
  126.       , nl = l.replace(/\\\./g, '.')
  127.     parts.forEach(function (part, _, __) {
  128.       if (!p[part] || typeof p[part] !== "object") p[part] = {}
  129.       p = p[part]
  130.     })
  131.     if (p === out && nl === l) return false
  132.     p[nl] = out[k]
  133.     return true
  134.   }).forEach(function (del, _, __) {
  135.     delete out[del]
  136.   })
  137.  
  138.   return out
  139. }
  140.  
  141. function isQuoted (val) {
  142.   return (val.charAt(0) === "\"" && val.slice(-1) === "\"")
  143.          || (val.charAt(0) === "'" && val.slice(-1) === "'")
  144. }
  145.  
  146. function safe (val) {
  147.   return ( typeof val !== "string"
  148.          || val.match(/[=\r\n]/)
  149.          || val.match(/^\[/)
  150.          || (val.length > 1
  151.              && isQuoted(val))
  152.          || val !== val.trim() )
  153.          ? JSON.stringify(val)
  154.          : val.replace(/;/g, '\\;').replace(/#/g, "\\#")
  155. }
  156.  
  157. function unsafe (val, doUnesc) {
  158.   val = (val || "").trim()
  159.   if (isQuoted(val)) {
  160.     // remove the single quotes before calling JSON.parse
  161.     if (val.charAt(0) === "'") {
  162.       val = val.substr(1, val.length - 2);
  163.     }
  164.     try { val = JSON.parse(val) } catch (_) {}
  165.   } else {
  166.     // walk the val to find the first not-escaped ; character
  167.     var esc = false
  168.     var unesc = "";
  169.     for (var i = 0, l = val.length; i < l; i++) {
  170.       var c = val.charAt(i)
  171.       if (esc) {
  172.         if ("\\;#".indexOf(c) !== -1)
  173.           unesc += c
  174.         else
  175.           unesc += "\\" + c
  176.         esc = false
  177.       } else if (";#".indexOf(c) !== -1) {
  178.         break
  179.       } else if (c === "\\") {
  180.         esc = true
  181.       } else {
  182.         unesc += c
  183.       }
  184.     }
  185.     if (esc)
  186.       unesc += "\\"
  187.     return unesc
  188.   }
  189.   return val
  190. }

Paste-bin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.