Skip to content

Commit

Permalink
Merge pull request #20 from MailOnline/feat/objectAsKeys
Browse files Browse the repository at this point in the history
Feat: obectsKeysAs feature
  • Loading branch information
jorinvo authored Nov 8, 2023
2 parents 92d5653 + 3cd3f5d commit ed13dff
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
40 changes: 38 additions & 2 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface ParseOptions {
keywordAs?: 'object' | 'string';
charAs?: 'object' | 'string';
tagHandlers?: { [tag: string]: (val: unknown) => unknown };
objectKeysAs?: 'object' | 'string'
}

enum ParseMode {
Expand Down Expand Up @@ -57,6 +58,7 @@ export class EDNListParser {
charAs: ParseOptions['charAs'];
listAs: ParseOptions['listAs'];
tagHandlers: ParseOptions['tagHandlers'];
objectKeysAs: ParseOptions['objectKeysAs'];

constructor({
mapAs = 'doubleArray',
Expand All @@ -65,12 +67,14 @@ export class EDNListParser {
charAs = 'object',
listAs = 'object',
tagHandlers = {},
objectKeysAs
}: ParseOptions = {}) {
this.mapAs = mapAs;
this.setAs = setAs;
this.keywordAs = keywordAs;
this.charAs = charAs;
this.listAs = listAs;
this.objectKeysAs = objectKeysAs;
this.tagHandlers = { ...defaultTagHandlers, ...tagHandlers };
}

Expand Down Expand Up @@ -201,9 +205,41 @@ export class EDNListParser {
if (stackItem === StackItem.map) {
// TODO: What if map is closed too early?
if (this.mapAs === 'object') {
// TODO: what if map has non-stringable keys? keys as JSON?
this.result = prevState[0].reduce((memo, [k, v]) => {
return { ...memo, [k]: v };
let key = k;
let value = v;
/**
* This setting ensures the back-compatibility
*
* The problem: Our EDN source will provide me the following
* [407 {:someKey "lovely-value"}] #{123}
*
* The existing behavior will serialize that to:
* [407,[object Object]]: [123]
* which is both invalid and prone to key clashes
*
* In presence of the new option the whole key will be stringified as JSON to resolve both problems.
* '[407,{"someKey":"lovely-value"}]': [123]
*
* That will make the key unique and readable and won't change the value format
*
* For option value 'object' we will go one step further to wrap the pair in easy to access object
*
* '[407,{"someKey":"lovely-value"}]': {
* key: [407, {someKey: "lovey-value"}],
* value: [123]
* }
*/
if (typeof k === 'object' && this.objectKeysAs) {
key = JSON.stringify(k);
if (this.objectKeysAs === 'object') {
value = {
key: k,
value
};
}
}
return { ...memo, [key]: value };
}, {});
} else if (this.mapAs === 'map') {
this.result = new Map(prevState[0]);
Expand Down
35 changes: 35 additions & 0 deletions test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,3 +606,38 @@ test('readme exsample', (t) => {
},
);
});

test('objectKeys as string', (t) => {
t.deepEqual(
parseEDNString('{[407 {:someKey "lovely-value"}] #{123}}', {
charAs: 'string',
keywordAs: 'string',
listAs: 'object',
mapAs: 'object',
setAs: 'array',
objectKeysAs: 'string',
}),
{
'[407,{"someKey":"lovely-value"}]': [123],
},
);
});

test('objectKeys as object', (t) => {
t.deepEqual(
parseEDNString('{[407 {:someKey "lovely-value"}] #{123}}', {
charAs: 'string',
keywordAs: 'string',
listAs: 'object',
mapAs: 'object',
setAs: 'array',
objectKeysAs: 'object',
}),
{
'[407,{"someKey":"lovely-value"}]': {
key: [407, { someKey: 'lovely-value' }],
value: [123],
},
},
);
});

0 comments on commit ed13dff

Please sign in to comment.