Skip to content

Commit

Permalink
fixed string encode/decode
Browse files Browse the repository at this point in the history
  • Loading branch information
asmyshlyaev177 committed Jun 26, 2024
1 parent 0e2485b commit 2b6a0d0
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 37 deletions.
7 changes: 2 additions & 5 deletions packages/encoder/constants.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
export const SYMBOLS = {
boolean: '🗵',
null: '∙',
undefined: '∙',
null: '∙null',
undefined: '∙undefined',
number: '∓',
arrayL: '⦋',
arrayR: '⦌',
objectL: '❴',
objectR: '❵',
};

export const NULL = SYMBOLS.null + 'null';
export const UNDEFINED = SYMBOLS.undefined + 'undefined';
103 changes: 82 additions & 21 deletions packages/encoder/encoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,56 @@ import { encode, decode } from './encoder';
describe('encoder', () => {
describe('string', () => {
it('simple', () => {
expect(encode('')).toEqual('');
expect(encode('test')).toEqual('test');
expect(encode('')).toStrictEqual('');
expect(encode('test')).toStrictEqual('test');
});

it('special characters', () => {
expect(encode('"test #?\t=\n[]{}()%.')).toEqual(
expect(encode('"test #?\t=\n[]{}()%.')).toStrictEqual(
'%22test%20%23%3F%09%3D%0A%5B%5D%7B%7D()%25.',
);
});
});

describe('number', () => {
it('integer and float', () => {
expect(encode(5)).toEqual('∓5');
expect(encode(5.55)).toEqual('∓5.55');
expect(encode(5)).toStrictEqual('∓5');
expect(encode(5.55)).toStrictEqual('∓5.55');
});
});

it('boolean', () => {
expect(encode(true)).toEqual('🗵true');
expect(encode(false)).toEqual('🗵false');
expect(encode(true)).toStrictEqual('🗵true');
expect(encode(false)).toStrictEqual('🗵false');
});

it('null', () => {
expect(encode(null)).toEqual('∙null');
expect(encode(null)).toStrictEqual('∙null');
});

it('undefined', () => {
expect(encode(undefined)).toEqual('∙undefined');
expect(encode(undefined)).toStrictEqual('∙undefined');
});

describe('object', () => {
it('simple', () => {
expect(encode({ num: 123, float: 1.55, bool1: false })).toEqual(
expect(encode({ num: 123, float: 1.55, bool1: false })).toStrictEqual(
"❴'num':'∓123','float':'∓1.55','bool1':'🗵false'❵",
);
});

it('nested', () => {
expect(encode({ num: 123, obj1: { obj2: { str: 'my_str' } } })).toEqual(
"❴'num':'∓123','obj1':❴'obj2':❴'str':'my_str'❵❵❵",
);
expect(
encode({ num: 123, obj1: { obj2: { str: 'my_str' } } }),
).toStrictEqual("❴'num':'∓123','obj1':❴'obj2':❴'str':'my_str'❵❵❵");
});
});

describe('array', () => {
it('simple', () => {
expect(encode([123, 1.55, false])).toEqual("⦋'∓123','∓1.55','🗵false'⦌");
expect(encode([123, 1.55, false])).toStrictEqual(
"⦋'∓123','∓1.55','🗵false'⦌",
);
});

it('nested', () => {
Expand All @@ -59,40 +61,99 @@ describe('encoder', () => {
123,
[45, true, { arr: [1, 2, { test: true }, null, undefined] }],
]),
).toEqual(
).toStrictEqual(
"⦋'∓123',⦋'∓45','🗵true',❴'arr':⦋'∓1','∓2',❴'test':'🗵true'❵,'∙null','∙undefined'⦌❵⦌⦌",
);
});
});

// no sense to handle this
it('function', () => {
expect(encode(() => {})).toEqual('');
expect(encode(() => {})).toStrictEqual('');
});

it('symbol', () => {
expect(encode(Symbol('a'))).toEqual('');
expect(encode(Symbol('a'))).toStrictEqual('');
});
});

describe('decoder', () => {
it('simple', () => {
expect(decode('test123')).toEqual('test123');
expect(decode('test123')).toStrictEqual('test123');
expect(decode('∙undefined')).toStrictEqual(undefined);
});

it('complex', () => {
expect(
decode(
"⦋'∓123',⦋'∓45','🗵true','🗵false',❴'arr':⦋'∓1','∓2',❴'b1':'🗵false','b2':'🗵true'❵,'∙null','∙undefined'⦌❵⦌⦌",
"⦋'∓123',⦋'∓45','🗵true','🗵false',❴'arr':⦋'∓1','∓2',❴'b1':'🗵false','b2':'🗵true'❵,'∙null'⦌❵⦌⦌",
),
).toEqual([
).toStrictEqual([
123,
[
45,
true,
false,
{ arr: [1, 2, { b1: false, b2: true }, null, undefined] },
{
arr: [1, 2, { b1: false, b2: true }, null],
},
],
]);
});
});

describe('real life example', () => {
const bigObj = {
emails: {
sha1: [
'f37224933f5e906904ef1f9aeca3486941664555',
'8a3c1b25c63e3a402e5e3a8e981054ddfec20a18',
],
sha256: [
'9d67f9cab3b2775dbe38e9f6521c23d20037391c0879e4700fea9e9a7672a79e',
'65c4bbea793b0ac3d5adb86beac555294df2aac05c932374d1d2e382bfd3ea4c',
],
},
client: {
deviceType: 'Personal computer',
browserLanguage: 'en-GB',
isUserLoggedIn: true,
countryCode: 'ge',
isInternalRequest: false,
},
id: { dmp: 'AT56sgZZhNi6E_vvdRIAFf-HXftr&v=2' },
numb1: 100500,
numb2: 100.12345,
compliance: {
isCCPAOptIn: true,
isLinkedInEmployee: false,
isFunctionalOptIn: true,
isGeoOptIn: true,
isGDPROptIn: true,
isAdvertisingOptIn: true,
isAnalyticsAndResearchOptIn: true,
},
primaryEmail: {
sha1: 'f37224933f5e906904ef1f9aeca3486941664555',
sha256:
'9d67f9cab3b2775dbe38e9f6521c23d20037391c0879e4700fea9e9a7672a79e',
},
preference: { language: 'en-us' },
};
const encoded =
"❴'emails':❴'sha1':⦋'f37224933f5e906904ef1f9aeca3486941664555','8a3c1b25c63e3a402e5e3a8e981054ddfec20a18'⦌,'sha256':⦋'9d67f9cab3b2775dbe38e9f6521c23d20037391c0879e4700fea9e9a7672a79e','65c4bbea793b0ac3d5adb86beac555294df2aac05c932374d1d2e382bfd3ea4c'⦌❵,'client':❴'deviceType':'Personal%20computer','browserLanguage':'en-GB','isUserLoggedIn':'🗵true','countryCode':'ge','isInternalRequest':'🗵false'❵,'id':❴'dmp':'AT56sgZZhNi6E_vvdRIAFf-HXftr%26v%3D2'❵,'numb1':'∓100500','numb2':'∓100.12345','compliance':❴'isCCPAOptIn':'🗵true','isLinkedInEmployee':'🗵false','isFunctionalOptIn':'🗵true','isGeoOptIn':'🗵true','isGDPROptIn':'🗵true','isAdvertisingOptIn':'🗵true','isAnalyticsAndResearchOptIn':'🗵true'❵,'primaryEmail':❴'sha1':'f37224933f5e906904ef1f9aeca3486941664555','sha256':'9d67f9cab3b2775dbe38e9f6521c23d20037391c0879e4700fea9e9a7672a79e'❵,'preference':❴'language':'en-us'❵❵";
it('encode', () => {
let a1 = performance.now();
const result = encode(bigObj);
let a2 = performance.now();
console.log('encode time', a2 - a1);
expect(result).toEqual(encoded);
});
it('decode', () => {
let a1 = performance.now();
const result = decode(encoded);
let a2 = performance.now();
expect(result).toStrictEqual(bigObj);
console.log('decode time ', a2 - a1);
});
});
14 changes: 7 additions & 7 deletions packages/encoder/encoder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { typeOf } from './utils';
import { SYMBOLS, NULL, UNDEFINED } from './constants';
import { SYMBOLS } from './constants';

export const encode = (payload: unknown): string => {
const type = typeOf(payload);
Expand All @@ -18,9 +18,9 @@ export const encode = (payload: unknown): string => {
case 'array':
return encodeObject(payload as object);
case 'null':
return NULL;
return SYMBOLS.null;
case 'undefined':
return UNDEFINED;
return SYMBOLS.undefined;
default:
return String(payload as string);
}
Expand All @@ -41,11 +41,11 @@ const replacer = (key: string, value: unknown) => {
};

const decodeStr = (str: string) => {
if (str.match(/^/)) return Number.parseInt(str.replaceAll('∓', ''));
if (str.match(/^/)) return Number.parseFloat(str.replaceAll('∓', ''));
if (str.match(/^🗵/)) return str.includes('true') ? true : false;
if (str === NULL) return null;
if (str === UNDEFINED) return undefined;
return str;
if (str === SYMBOLS.null) return null;
if (str === SYMBOLS.undefined) return undefined;
return decodeURIComponent(str);
};

const reviver = (key: string, value: unknown) => {
Expand Down
7 changes: 3 additions & 4 deletions todo
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
bundler - tsc or rollup ?
npm workspaces
parser/stringifier modules
react, svelte, vue bindings in packages
TODO:
react, NextJS, svelte, vue bindings in packages
landing page in gh-pages

NOTES:
Only invalid characters are - "<>^`{|} and control characters like newline and tab
https://stackoverflow.com/questions/1547899/which-characters-make-a-url-invalid
standard - https://url.spec.whatwg.org/

0 comments on commit 2b6a0d0

Please sign in to comment.