dot-properties
Advanced tools
Comparing version 0.3.1 to 0.3.2
{ | ||
"name": "dot-properties", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"main": "index.js", | ||
@@ -20,2 +20,3 @@ "license": "MIT", | ||
"scripts": { | ||
"lint": "eslint .", | ||
"test": "jest" | ||
@@ -28,5 +29,13 @@ }, | ||
}, | ||
"prettier": { | ||
"semi": false, | ||
"singleQuote": true | ||
}, | ||
"devDependencies": { | ||
"jest": "^24.5.0" | ||
"eslint": "^6.0.1", | ||
"eslint-config-prettier": "^6.0.0", | ||
"eslint-plugin-prettier": "^3.1.0", | ||
"jest": "^24.8.0", | ||
"prettier": "^1.18.2" | ||
} | ||
} |
68
parse.js
@@ -31,3 +31,12 @@ const atComment = (src, offset) => { | ||
let ch = src[offset] | ||
while (ch && ch !== '\r' && ch !== '\n' && ch !== '\t' && ch !== '\f' && ch !== ' ' && ch !== ':' && ch !== '=') { | ||
while ( | ||
ch && | ||
ch !== '\r' && | ||
ch !== '\n' && | ||
ch !== '\t' && | ||
ch !== '\f' && | ||
ch !== ' ' && | ||
ch !== ':' && | ||
ch !== '=' | ||
) { | ||
if (ch === '\\') { | ||
@@ -50,3 +59,10 @@ if (src[offset + 1] === '\n') { | ||
let hasEqSign = false | ||
loop: while (ch === '\t' || ch === '\f' || ch === ' ' || ch === '=' || ch === ':' || ch === '\\') { | ||
loop: while ( | ||
ch === '\t' || | ||
ch === '\f' || | ||
ch === ' ' || | ||
ch === '=' || | ||
ch === ':' || | ||
ch === '\\' | ||
) { | ||
switch (ch) { | ||
@@ -61,3 +77,3 @@ case '\\': | ||
hasEqSign = true | ||
// fallthrough | ||
// fallthrough | ||
default: | ||
@@ -80,19 +96,25 @@ offset += 1 | ||
const unescape = (str) => str.replace(/\\(u[0-9a-fA-F]{4}|\r?\n[ \t\f]*|.)?/g, (match, code) => { | ||
switch (code && code[0]) { | ||
case 'f': return '\f' | ||
case 'n': return '\n' | ||
case 'r': return '\r' | ||
case 't': return '\t' | ||
case 'u': | ||
const c = parseInt(code.substr(1), 16) | ||
return isNaN(c) ? code : String.fromCharCode(c) | ||
case '\r': | ||
case '\n': | ||
case undefined: | ||
return '' | ||
default: | ||
return code | ||
} | ||
}) | ||
const unescape = str => | ||
str.replace(/\\(u[0-9a-fA-F]{4}|\r?\n[ \t\f]*|.)?/g, (match, code) => { | ||
switch (code && code[0]) { | ||
case 'f': | ||
return '\f' | ||
case 'n': | ||
return '\n' | ||
case 'r': | ||
return '\r' | ||
case 't': | ||
return '\t' | ||
case 'u': { | ||
const c = parseInt(code.substr(1), 16) | ||
return isNaN(c) ? code : String.fromCharCode(c) | ||
} | ||
case '\r': | ||
case '\n': | ||
case undefined: | ||
return '' | ||
default: | ||
return code | ||
} | ||
}) | ||
@@ -112,5 +134,5 @@ /** | ||
*/ | ||
function parseLines (src) { | ||
function parseLines(src) { | ||
const lines = [] | ||
for (i = 0; i < src.length; ++i) { | ||
for (let i = 0; i < src.length; ++i) { | ||
if (src[i] === '\n' && src[i - 1] === '\r') i += 1 | ||
@@ -159,3 +181,3 @@ if (!src[i]) break | ||
*/ | ||
function parse (src, path) { | ||
function parse(src, path) { | ||
const pathSep = typeof path === 'string' ? path : '.' | ||
@@ -162,0 +184,0 @@ return parseLines(src).reduce((res, line) => { |
@@ -57,7 +57,7 @@ # dot-properties | ||
# the value onto the next line. | ||
message = Welcome to \\ | ||
message = Welcome to \ | ||
Wikipedia! | ||
# Add spaces to the key | ||
key\\ with\\ spaces = This is the value that could be looked up with \\ | ||
key\ with\ spaces = This is the value that could be looked up with \ | ||
the key "key with spaces". | ||
@@ -64,0 +64,0 @@ |
const escapeNonPrintable = (str, latin1) => { | ||
const re = latin1 !== false ? /[^\t\n\f\r -~\xa1-\xff]/g : /[\0-\b\v\x0e-\x1f]/g | ||
return String(str).replace(re, (ch) => { | ||
const re = | ||
latin1 !== false ? /[^\t\n\f\r -~\xa1-\xff]/g : /[\0-\b\v\x0e-\x1f]/g | ||
return String(str).replace(re, ch => { | ||
const esc = ch.charCodeAt(0).toString(16) | ||
@@ -9,14 +10,15 @@ return '\\u' + ('0000' + esc).slice(-4) | ||
const escape = (str) => String(str) | ||
.replace(/\\/g, '\\\\') | ||
.replace(/\f/g, '\\f') | ||
.replace(/\n/g, '\\n') | ||
.replace(/\r/g, '\\r') | ||
.replace(/\t/g, '\\t') | ||
const escape = str => | ||
String(str) | ||
.replace(/\\/g, '\\\\') | ||
.replace(/\f/g, '\\f') | ||
.replace(/\n/g, '\\n') | ||
.replace(/\r/g, '\\r') | ||
.replace(/\t/g, '\\t') | ||
const escapeKey = (str) => escape(str).replace(/[ =:]/g, '\\$&') | ||
const escapeKey = str => escape(str).replace(/[ =:]/g, '\\$&') | ||
const escapeValue = (str) => escape(str).replace(/^ /, '\\ ') | ||
const escapeValue = str => escape(str).replace(/^ /, '\\ ') | ||
const getFold = ({ indent, latin1, lineWidth, newline }) => (line) => { | ||
const getFold = ({ indent, latin1, lineWidth, newline }) => line => { | ||
if (!lineWidth || lineWidth < 0) return line | ||
@@ -26,3 +28,3 @@ line = escapeNonPrintable(line, latin1) | ||
let split = undefined | ||
for (let i = 0, ch = line[0]; ch; ch = line[i += 1]) { | ||
for (let i = 0, ch = line[0]; ch; ch = line[(i += 1)]) { | ||
let end = i - start >= lineWidth ? split || i : undefined | ||
@@ -33,3 +35,3 @@ if (!end) { | ||
if (line[i + 1] === '\n') i += 1 | ||
// fallthrough | ||
// fallthrough | ||
case '\n': | ||
@@ -43,3 +45,3 @@ end = i + 1 | ||
if (line[i + 1] === '\\' && line[i + 2] === 'n') i += 2 | ||
// fallthrough | ||
// fallthrough | ||
case 'n': | ||
@@ -71,4 +73,9 @@ end = i + 1 | ||
const next = line[end] | ||
const atWhitespace = (next === '\t' || next === '\f' || next === ' ') | ||
line = line.slice(0, lineEnd) + newline + indent + (atWhitespace ? '\\' : '') + line.slice(end) | ||
const atWhitespace = next === '\t' || next === '\f' || next === ' ' | ||
line = | ||
line.slice(0, lineEnd) + | ||
newline + | ||
indent + | ||
(atWhitespace ? '\\' : '') + | ||
line.slice(end) | ||
start = lineEnd + newline.length | ||
@@ -86,5 +93,8 @@ split = undefined | ||
if (value && typeof value === 'object') { | ||
return lines.concat(toLines(value, pathSep, defaultKey, prefix + key + pathSep)) | ||
return lines.concat( | ||
toLines(value, pathSep, defaultKey, prefix + key + pathSep) | ||
) | ||
} else { | ||
const k = key === defaultKey ? prefix.slice(0, -(pathSep.length)) : prefix + key | ||
const k = | ||
key === defaultKey ? prefix.slice(0, -pathSep.length) : prefix + key | ||
lines.push([k, value]) | ||
@@ -123,16 +133,29 @@ return lines | ||
*/ | ||
function stringify (input, { | ||
commentPrefix = '# ', | ||
defaultKey = '', | ||
indent = ' ', | ||
keySep = ' = ', | ||
latin1 = true, | ||
lineWidth = 80, | ||
newline = '\n', | ||
pathSep = '.' | ||
} = {}) { | ||
function stringify( | ||
input, | ||
{ | ||
commentPrefix = '# ', | ||
defaultKey = '', | ||
indent = ' ', | ||
keySep = ' = ', | ||
latin1 = true, | ||
lineWidth = 80, | ||
newline = '\n', | ||
pathSep = '.' | ||
} = {} | ||
) { | ||
if (!input) return '' | ||
if (!Array.isArray(input)) input = toLines(input, pathSep, defaultKey) | ||
const foldLine = getFold({ indent, latin1, lineWidth, newline: '\\' + newline }) | ||
const foldComment = getFold({ indent: commentPrefix, latin1, lineWidth, newline }) | ||
const foldLine = getFold({ | ||
indent, | ||
latin1, | ||
lineWidth, | ||
newline: '\\' + newline | ||
}) | ||
const foldComment = getFold({ | ||
indent: commentPrefix, | ||
latin1, | ||
lineWidth, | ||
newline | ||
}) | ||
return input | ||
@@ -143,9 +166,11 @@ .map(line => { | ||
return '' | ||
case Array.isArray(line): | ||
case Array.isArray(line): { | ||
const key = escapeKey(line[0]) | ||
const value = escapeValue(line[1]) | ||
return foldLine(key + keySep + value) | ||
default: | ||
} | ||
default: { | ||
const cc = String(line).replace(/^\s*([#!][ \t\f]*)?/g, commentPrefix) | ||
return foldComment(cc) | ||
} | ||
} | ||
@@ -152,0 +177,0 @@ }) |
17980
366
5