Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
build:
strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 15.x]
node-version: [10.x, 12.x, 14.x, 15.x, 16.x]
platform:
- os: ubuntu-latest
- os: macos-latest
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ 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.
* `withoutArraySuffix` Boolean to specify whether to insert `[]` as array properties. default is `false`.

For backwards compatibility reasons, if a `string` options is passed
in, then it is assumed to be the `section` value.
Expand Down
27 changes: 18 additions & 9 deletions lib/ini.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ const encode = (obj, opt) => {
opt = {
section: opt,
whitespace: false,
withoutArraySuffix: false,
}
} else {
opt = opt || Object.create(null)
opt.whitespace = opt.whitespace === true
opt.withoutArraySuffix = opt.withoutArraySuffix === true
}

const separator = opt.whitespace ? ' = ' : '='
const arraySuffix = opt.withoutArraySuffix ? '' : '[]'

for (const k of Object.keys(obj)) {
const val = obj[k]
if (val && Array.isArray(val)) {
for (const item of val)
out += safe(k + '[]') + separator + safe(item) + eol
out += safe(k + arraySuffix) + separator + safe(item) + eol
} else if (val && typeof val === 'object')
children.push(k)
else
Expand All @@ -37,10 +40,11 @@ const encode = (obj, opt) => {
for (const k of children) {
const nk = dotSplit(k).join('\\.')
const section = (opt.section ? opt.section + '.' : '') + nk
const { whitespace } = opt
const { whitespace, withoutArraySuffix } = opt
const child = encode(obj[k], {
section,
whitespace,
withoutArraySuffix,
})
if (out.length && child.length)
out += eol
Expand All @@ -59,13 +63,15 @@ const dotSplit = str =>
part.replace(/\1/g, '\\.')
.replace(/\2LITERAL\\1LITERAL\2/g, '\u0001'))

const decode = str => {
const decode = (str, opt) => {
const out = Object.create(null)
let p = out
let section = null
// section |key = value
const re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i
const lines = str.split(/[\r\n]+/g)
// for duplicate property statist
const bucket = {}

for (const line of lines) {
if (!line || line.match(/^\s*[;#]/))
Expand All @@ -85,8 +91,11 @@ const decode = str => {
continue
}
const keyRaw = unsafe(match[2])
const isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]'
let isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]'
const key = isArray ? keyRaw.slice(0, -2) : keyRaw
bucket[key] = ~~bucket[key] + 1
if (opt && opt.withoutArraySuffix && bucket[key] > 1)
isArray = true
if (key === '__proto__')
continue
const valueRaw = match[3] ? unsafe(match[4]) : true
Expand Down Expand Up @@ -116,8 +125,8 @@ const decode = str => {
const remove = []
for (const k of Object.keys(out)) {
if (!hasOwnProperty.call(out, k) ||
typeof out[k] !== 'object' ||
Array.isArray(out[k]))
typeof out[k] !== 'object' ||
Array.isArray(out[k]))
continue

// see if the parent section is also an object.
Expand Down Expand Up @@ -147,14 +156,14 @@ const decode = str => {

const isQuoted = val =>
(val.charAt(0) === '"' && val.slice(-1) === '"') ||
(val.charAt(0) === "'" && val.slice(-1) === "'")
(val.charAt(0) === "'" && val.slice(-1) === "'")

const safe = val =>
(typeof val !== 'string' ||
val.match(/[=\r\n]/) ||
val.match(/^\[/) ||
(val.length > 1 &&
isQuoted(val)) ||
isQuoted(val)) ||
val !== val.trim())
? JSON.stringify(val)
: val.replace(/;/g, '\\;').replace(/#/g, '\\#')
Expand All @@ -168,7 +177,7 @@ const unsafe = (val, doUnesc) => {

try {
val = JSON.parse(val)
} catch (_) {}
} catch (_) { }
} else {
// walk the val to find the first not-escaped ; character
let esc = false
Expand Down
111 changes: 0 additions & 111 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions tap-snapshots/test/foo.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ Null Object {
"this is included",
],
"br": "warm",
"duplicate": Null Object {
"ar": Array [
"2",
"3",
],
"br": "2",
},
"eq": "eq=eq",
"false": false,
"null": null,
Expand Down Expand Up @@ -100,6 +107,11 @@ cr[]=eight
e=1
j=2

[duplicate]
ar[]=2
ar[]=3
br=2

[x\\.y\\.z]
x.y.z=xyz

Expand Down
Loading