-
Notifications
You must be signed in to change notification settings - Fork 206
feat: support parse and stringify with comments #247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3e3d9e2
6e2190c
2e835c4
bd7f21e
77b762a
c199a7e
79f6d72
69c7264
9c83f30
040639c
8ae5a06
f17c0ee
4213a94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| const { hasOwnProperty } = Object.prototype | ||
| const COMMENTS_ID = Symbol.for('comments_id') | ||
|
|
||
| const encode = (obj, opt = {}) => { | ||
| if (typeof opt === 'string') { | ||
|
|
@@ -12,6 +13,8 @@ const encode = (obj, opt = {}) => { | |
| /* istanbul ignore next */ | ||
| opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform) | ||
| opt.bracketedArray = opt.bracketedArray !== false | ||
| const preserveComments = opt.preserveComments || false | ||
| const commentsDictionary = hasOwnProperty.call(obj, COMMENTS_ID) ? obj[COMMENTS_ID] : {} | ||
|
|
||
| /* istanbul ignore next */ | ||
| const eol = opt.platform === 'win32' ? '\r\n' : '\n' | ||
|
|
@@ -46,24 +49,40 @@ const encode = (obj, opt = {}) => { | |
| for (const k of keys) { | ||
| const val = obj[k] | ||
| if (val && Array.isArray(val)) { | ||
| if (preserveComments && hasOwnProperty.call(commentsDictionary, k)) { | ||
| out += commentsDictionary[k] | ||
| } | ||
| for (const item of val) { | ||
| out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol | ||
| } | ||
| } else if (val && typeof val === 'object') { | ||
| children.push(k) | ||
| } else { | ||
| if (preserveComments && hasOwnProperty.call(commentsDictionary, k)) { | ||
| out += commentsDictionary[k] | ||
| } | ||
| out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol | ||
| } | ||
| } | ||
|
|
||
| if (opt.section && out.length) { | ||
| out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out | ||
| let sectionComments = '' | ||
| if (preserveComments && hasOwnProperty.call(commentsDictionary, opt.section)) { | ||
| sectionComments = commentsDictionary[opt.section] | ||
| } | ||
| out = sectionComments + '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out | ||
| } | ||
|
|
||
| for (const k of children) { | ||
| if (/comments/.test(k)) { | ||
| continue | ||
| } | ||
| const nk = splitSections(k, '.').join('\\.') | ||
| const section = (opt.section ? opt.section + '.' : '') + nk | ||
| const child = encode(obj[k], { | ||
| const childObject = hasOwnProperty.call(obj, COMMENTS_ID) ? | ||
| Object.assign(obj[k], { [COMMENTS_ID]: obj[COMMENTS_ID] }) : | ||
| obj[k] | ||
| const child = encode(childObject, { | ||
| ...opt, | ||
| section, | ||
| }) | ||
|
|
@@ -104,16 +123,26 @@ function splitSections (str, separator) { | |
| } | ||
|
|
||
| const decode = (str, opt = {}) => { | ||
| // The `typeof` check is required because accessing the `process` directly fails on browsers. | ||
| /* istanbul ignore next */ | ||
| opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform) | ||
wraithgar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /* istanbul ignore next */ | ||
| const eol = opt.platform === 'win32' ? '\r\n' : '\n' | ||
| opt.bracketedArray = opt.bracketedArray !== false | ||
| const out = Object.create(null) | ||
| let p = out | ||
| let section = null | ||
| const commentsDictionary = {} | ||
| let lineCommentArray = [] | ||
| // section |key = value | ||
| const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i | ||
| const lines = str.split(/[\r\n]+/g) | ||
| const duplicates = {} | ||
|
|
||
| for (const line of lines) { | ||
| if (line && line.match(/^[#;]/)) { | ||
| lineCommentArray.push(line) | ||
| } | ||
| if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) { | ||
wraithgar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| continue | ||
| } | ||
|
|
@@ -130,6 +159,10 @@ const decode = (str, opt = {}) => { | |
| continue | ||
| } | ||
| p = out[section] = out[section] || Object.create(null) | ||
| if (lineCommentArray.length > 0) { | ||
| commentsDictionary[section] = lineCommentArray.join(eol) + eol | ||
| lineCommentArray = [] | ||
| } | ||
| continue | ||
| } | ||
| const keyRaw = unsafe(match[2]) | ||
|
|
@@ -163,8 +196,16 @@ const decode = (str, opt = {}) => { | |
| // array by accidentally forgetting the brackets | ||
| if (Array.isArray(p[key])) { | ||
| p[key].push(value) | ||
| if (lineCommentArray.length > 0) { | ||
| commentsDictionary[key] = lineCommentArray.join(eol) + eol | ||
| lineCommentArray = [] | ||
| } | ||
| } else { | ||
| p[key] = value | ||
| if (lineCommentArray.length > 0) { | ||
| commentsDictionary[key] = lineCommentArray.join(eol) + eol | ||
| lineCommentArray = [] | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -204,6 +245,8 @@ const decode = (str, opt = {}) => { | |
| delete out[del] | ||
| } | ||
|
|
||
| out[COMMENTS_ID] = commentsDictionary | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this will work because the Here's an example: I think the best strategy here would be to follow what Another option would be new methods like |
||
| return out | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,3 +94,9 @@ test('encode within browser context', function (t) { | |
| t.matchSnapshot(e) | ||
| t.end() | ||
| }) | ||
| test('stringify with comments', function (t) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. .decode |
||
| const d = i.parse(data) | ||
| const s = i.stringify(d, { preserveComments: true }) | ||
| t.matchSnapshot(s) | ||
| t.end() | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool
/