Skip to content

Commit 09e3977

Browse files
committed
feat: Add an option for reporting duplicate object keys as an error
1 parent 7d521fb commit 09e3977

File tree

8 files changed

+31
-8
lines changed

8 files changed

+31
-8
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"type": "node",
2020
"request": "launch",
2121
"name": "test",
22-
"program": "${workspaceRoot}/test/parse1.js",
22+
"program": "${workspaceRoot}/test/parse2.js",
2323
"args": [
2424
"--native-parser"
2525
],

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This is a fork of the original package with the following enhancements:
1515
* Walks directories recursively (by Paul Vollmer).
1616
* Provides 100% compatible interface to the native `JSON.parse` method.
1717
* Optionally recognizes JavaScript-style comments and single quoted strings.
18-
* Optionally ignores trailing commas in objects and arrays.
18+
* Optionally ignores trailing commas and reports duplicate object keys as an error.
1919
* Supports [JSON Schema] drafts 04, 06 and 07.
2020
* Prefers the native JSON parser to gain the [best performance], while showing error messages of the same quality.
2121
* Implements JavaScript modules using [UMD] to work everywhere.
@@ -81,6 +81,7 @@ By default, `jsonlint` will either report a syntax error with details or pretty-
8181
-C, --comments recognize and ignore JavaScript-style comments
8282
-S, --single-quoted-strings support single quotes as string delimiters
8383
-T, --trailing-commas' ignore trailing commas in objects and arrays
84+
-D, --no-duplicate-keys report duplicate object keys as an error
8485
-V, --validate [file] JSON schema file to use for validation
8586
-e, --environment [env] which specification of JSON Schema
8687
the validation file uses
@@ -132,6 +133,7 @@ The `parse` method offers more detailed [error information](#error-handling), th
132133
| `ignoreComments` | ignores single-line and multi-line JavaScript-style comments during parsing as another "whitespace" (boolean) |
133134
| `ignoreTrailingCommas` | ignores trailing commas in objects and arrays (boolean) |
134135
| `allowSingleQuotedStrings` | accepts strings delimited by single-quotes too (boolean) |
136+
| `allowDuplicateObjectKeys` | allows reporting duplicate object keys as an error (boolean) |
135137
| `mode` | sets multiple options according to the type of input data (string) |
136138

137139
The `mode` parameter (string) sets parsing options to match a common format of input data:

lib/cli.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var options = require('commander')
2525
.option('-C, --comments', 'recognize and ignore JavaScript-style comments')
2626
.option('-S, --single-quoted-strings', 'support single quotes as string delimiters')
2727
.option('-T, --trailing-commas', 'ignore trailing commas in objects and arrays')
28+
.option('-D, --no-duplicate-keys', 'report duplicate object keys as an error')
2829
.option('-V, --validate [file]', 'JSON schema file to use for validation')
2930
.option('-e, --environment [env]', 'which specification of JSON Schema the validation file uses')
3031
.option('-q, --quiet', 'do not print the parsed json to stdin')
@@ -56,7 +57,8 @@ function parse (source, file) {
5657
mode: options.mode,
5758
ignoreComments: options.comments,
5859
ignoreTrailingCommas: options.trailingCommas,
59-
allowSingleQuotedStrings: options.singleQuotedStrings
60+
allowSingleQuotedStrings: options.singleQuotedStrings,
61+
allowDuplicateObjectKeys: options.duplicateKeys
6062
}
6163
parsed = parser.parse(source, parserOptions)
6264
if (options.sortKeys) {

lib/validator.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
mode: options.mode,
5858
ignoreComments: options.ignoreComments,
5959
ignoreTrailingCommas: options.ignoreTrailingCommas,
60-
allowSingleQuotedStrings: options.allowSingleQuotedStrings
60+
allowSingleQuotedStrings: options.allowSingleQuotedStrings,
61+
allowDuplicateObjectKeys: options.allowDuplicateObjectKeys
6162
})
6263
validate = ajv.compile(schema)
6364
} catch (error) {

src/configurable-parser.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ function processOptions (options) {
2222
changed.allowSingleQuotedStrings = this.allowSingleQuotedStrings
2323
this.allowSingleQuotedStrings = options.allowSingleQuotedStrings
2424
}
25+
if (options.allowDuplicateObjectKeys !== undefined) {
26+
changed.allowDuplicateObjectKeys = this.allowDuplicateObjectKeys
27+
this.allowDuplicateObjectKeys = options.allowDuplicateObjectKeys
28+
}
2529
if (options.mode !== undefined) {
2630
changed.mode = this.mode
2731
this.mode = options.mode
@@ -47,9 +51,9 @@ var isSafari = typeof navigator !== 'undefined' && /Safari/.test(navigator.userA
4751
var oldNode = typeof process !== 'undefined' && process.version.startsWith('v4.')
4852

4953
function needsCustomParser () {
50-
return this.ignoreComments || this.allowSingleQuotedStrings ||
51-
this.ignoreTrailingCommas || this.mode === 'cjson' || this.mode === 'json5' ||
52-
isSafari || oldNode
54+
return this.ignoreComments || this.ignoreTrailingCommas ||
55+
this.allowSingleQuotedStrings || this.allowDuplicateObjectKeys === false ||
56+
this.mode === 'cjson' || this.mode === 'json5' || isSafari || oldNode
5357
}
5458

5559
function getReviver (options) {

src/custom-parser.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ function parseCustom (input, options) { // eslint-disable-line no-unused-vars
4646
var ignoreComments = options.ignoreComments || options.mode === 'cjson' || json5
4747
var ignoreTrailingCommas = options.ignoreTrailingCommas || json5
4848
var allowSingleQuotedStrings = options.allowSingleQuotedStrings || json5
49+
var allowDuplicateObjectKeys = options.allowDuplicateObjectKeys
4950
var reviver = options.reviver
5051

5152
var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
@@ -227,6 +228,9 @@ function parseCustom (input, options) { // eslint-disable-line no-unused-vars
227228
while (position < inputLength) {
228229
skipWhiteSpace()
229230
var key = parseKey()
231+
if (allowDuplicateObjectKeys === false && result[key]) {
232+
fail('Duplicate key: ' + key)
233+
}
230234
skipWhiteSpace()
231235

232236
var char = input[position++]

test/parse2.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ addTest('[1,\r\n2,\r3,\n]')
152152

153153
assert.throws(parse.bind(null, '{-1:42}', { mode: 'json5' }))
154154

155+
assert.deepEqual(parse('{ "key": 1, "key": 2}'), { key: 2 })
156+
assert.throws(function () {
157+
parse('{ "key": 1, "key": 2}', { allowDuplicateObjectKeys: false })
158+
})
159+
155160
for (i = 0; i < 100; ++i) {
156161
var str = '-01.e'.split('')
157162

web/jsonlint.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ <h1>JSON Lint</h1>
104104
<input type="checkbox" id="single-quoted-strings">
105105
<label for="single-quoted-strings">Recognize single-quoted strings</label>
106106
</div>
107+
<div>
108+
<input type="checkbox" checked id="duplicate-object-keys">
109+
<label for="single-quoted-strings">Allow duplicate object keys</label>
110+
</div>
107111
<div>
108112
<input type="checkbox" id="with-schema">
109113
<label for="with-schema">Use schema</label>
@@ -144,7 +148,8 @@ <h2>Result</h2>
144148
var parserOptions = {
145149
ignoreComments: document.getElementById('comments').checked,
146150
ignoreTrailingCommas: document.getElementById('trailing-commas').checked,
147-
allowSingleQuotedStrings: document.getElementById('single-quoted-strings').checked
151+
allowSingleQuotedStrings: document.getElementById('single-quoted-strings').checked,
152+
allowDuplicateObjectKeys: document.getElementById('duplicate-object-keys').checked,
148153
}
149154
var parsed = parser.parse(document.getElementById('data').value, parserOptions)
150155
if (document.getElementById('with-schema').checked) {

0 commit comments

Comments
 (0)