Read the source and its declared rule
The original import requires unique decoded member names within each JSON object. Raw qty 2 then qty 3 parses here as one qty 3, but that is insufficient evidence to choose the intended source quantity. The local scanner first validates JSON syntax, then detects duplicate decoded names inside each object scope.
| Record | Input JSON |
|---|---|
| Base input | {"raw":"{\"qty\":2,\"qty\":3}"} |
Compare the actual paths
Good output holds the raw source and both-name collision evidence. The same member name in two different array objects is not a duplicate within one object.
| Path | Output JSON |
|---|---|
| Misleading path | {"accepted":true,"value":{"qty":3}} |
| Corrected path | {"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"qty\":3}"} |
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};
import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
const parsed=JSON.parse(i.raw);if(!corrected)return {accepted:true,value:parsed};
let at=0;const duplicateNames=[];
const space=()=>{while(/\s/.test(i.raw[at]??'')&&at<i.raw.length)at++;};
const string=()=>{const start=at++;while(at<i.raw.length){const c=i.raw[at++];if(c==='\\'){at++;continue;}if(c==='"')break;}return JSON.parse(i.raw.slice(start,at));};
const value=()=>{space();const token=i.raw[at];if(token==='"'){string();return;}
if(token==='{'){at++;space();const seen=new Set();if(i.raw[at]==='}'){at++;return;}
for(;;){space();const key=string();if(seen.has(key))duplicateNames.push(key);seen.add(key);space();at++;value();space();if(i.raw[at++]==='}')return;}}
if(token==='['){at++;space();if(i.raw[at]===']'){at++;return;}for(;;){value();space();if(i.raw[at++]===']')return;}}
while(at<i.raw.length&&!/[\s,\]}]/.test(i.raw[at]))at++;
};value();return duplicateNames.length?{accepted:false,error:'duplicate-json-members',duplicateNames,raw:i.raw}:{accepted:true,value:parsed};
};
const cases=[{"label":"misleading base","input":{"raw":"{\"qty\":2,\"qty\":3}"},"expected":{"accepted":true,"value":{"qty":3}},"corrected":false},{"label":"corrected base","input":{"raw":"{\"qty\":2,\"qty\":3}"},"expected":{"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"qty\":3}"},"corrected":true},{"label":"same name in separate objects","input":{"raw":"[{\"qty\":2},{\"qty\":3}]"},"expected":{"accepted":true,"value":[{"qty":2},{"qty":3}]},"corrected":true},{"label":"escaped equivalent member name","input":{"raw":"{\"qty\":2,\"q\\u0074y\":3}"},"expected":{"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"q\\u0074y\":3}"},"corrected":true}];
for(const test of cases){
const actual=run(test.input,test.corrected);
assert.deepEqual(actual,test.expected,test.label);
console.log(test.label,actual);
}
Check boundaries before the next load
Separate object scopes accept. An escaped spelling decoding to qty still collides with qty.
| Case | Input JSON | Expected output JSON |
|---|---|---|
| Name repeated across separate objects | {"raw":"[{\"qty\":2},{\"qty\":3}]"} | {"accepted":true,"value":[{"qty":2},{"qty":3}]} |
| Escaped name equals an earlier member | {"raw":"{\"qty\":2,\"q\\u0074y\":3}"} | {"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"q\\u0074y\":3}"} |
May qty 3 be accepted simply because the parser retained it?
Show the worked answer
No. The supplied admission rule rejects the repeated member and retains the complete raw JSON for correction.