From 9f583a5e5b20fdc69a4d3bc44e343006e5191f40 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 12 Apr 2023 23:19:53 -0500 Subject: [PATCH] ta: adding encode/decode --- src/index.ts | 1 + src/ta.ts | 93 +++++++++++++++++++++++++++++++++++++++ test/aura.test.ts | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 src/ta.ts diff --git a/src/index.ts b/src/index.ts index 2759f22..300498f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ export * from './da'; export * from './p'; export * from './q'; +export * from './ta'; export * from './ud'; export * from './uv'; export * from './uw'; diff --git a/src/ta.ts b/src/ta.ts new file mode 100644 index 0000000..1814510 --- /dev/null +++ b/src/ta.ts @@ -0,0 +1,93 @@ +/** + * encode the string into @ta-safe format, using logic from +wood. + * for example, 'some Chars!' becomes '~.some.~43.hars~21.' + * + * @param {String} str the string to encode + * @returns {String} the @ta encoded string + */ +export function encodeTa(str: string): string { + let out = ''; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + let add = ''; + switch (char) { + case ' ': + add = '.'; + break; + case '.': + add = '~.'; + break; + case '~': + add = '~~'; + break; + default: + const charCode = str.charCodeAt(i); + if ( + (charCode >= 97 && charCode <= 122) || // a-z + (charCode >= 48 && charCode <= 57) || // 0-9 + char === '-' + ) { + add = char; + } else { + // TODO behavior for unicode doesn't match +wood's, + // but we can probably get away with that for now. + add = '~' + charCode.toString(16) + '.'; + } + } + out = out + add; + } + return '~.' + out; +} + +/** + * decode @ta string previously encoded. for example, + * '~.some.~43.hars~21.' becomes 'some Chars!' + * + * @param {String} str the string to encode + * @returns {String} the @ta encoded string + */ +export function decodeTa(str: string): string { + let out = ''; + let strip = str.replace('~.', ''); + + while (strip.length > 0) { + const space = strip.match(/^\./); + if (space) { + strip = strip.slice(1); + out += ' '; + continue; + } + + const sig = strip.match(/^~~/); + if (sig) { + strip = strip.slice(2); + out += '~'; + continue; + } + + const period = strip.match(/^~\./); + if (period) { + strip = strip.slice(2); + out += '.'; + continue; + } + + const char = strip.match(/^~(\d{1,3})./); + if (char) { + strip = strip.replace(char[0], ''); + out += String.fromCharCode(parseInt(char[1], 16)); + continue; + } + + const normal = strip.match(/^[\w\d-]+/); + if (normal) { + strip = strip.replace(normal[0], ''); + out += normal[0]; + continue; + } + + throw new Error('Invalid @ta encoded string'); + } + + return out; +} diff --git a/test/aura.test.ts b/test/aura.test.ts index f4179ff..36526ab 100644 --- a/test/aura.test.ts +++ b/test/aura.test.ts @@ -9,6 +9,8 @@ import { formatUd, parseUx, formatUx, + encodeTa, + decodeTa, } from '../src'; import bigInt, { BigInteger } from 'big-integer'; @@ -38,6 +40,113 @@ describe('@da', () => { }); }); +const strings = { + symbols: { + str: '#fine()', + ta: '~.~23.fine~28.~29.', + }, + spaces: { + str: 'fine here', + ta: '~.fine.here', + }, + periods: { + str: 'fine.', + ta: '~.fine~.', + }, + sigs: { + str: '~fine', + ta: '~.~~fine', + }, + uppercase: { + str: 'Fine', + ta: '~.~46.ine', + }, + normal: { + str: 'fine-123', + ta: '~.fine-123', + }, + tricky: { + str: '~. F .~Yes', + ta: '~.~~~..~46..~.~~~59.es', + }, +}; + +describe('@ta', () => { + describe('encodeTa', () => { + it('encodes symbols', () => { + const res = encodeTa(strings.symbols.str); + expect(res).toEqual(strings.symbols.ta); + }); + + it('encodes spaces', () => { + const res = encodeTa(strings.spaces.str); + expect(res).toEqual(strings.spaces.ta); + }); + + it('encodes sigs', () => { + const res = encodeTa(strings.sigs.str); + expect(res).toEqual(strings.sigs.ta); + }); + + it('encodes periods', () => { + const res = encodeTa(strings.periods.str); + expect(res).toEqual(strings.periods.ta); + }); + + it('encodes uppercase characters', () => { + const res = encodeTa(strings.uppercase.str); + expect(res).toEqual(strings.uppercase.ta); + }); + + it("doesn't encode digits, lowercase, or dashes", () => { + const res = encodeTa(strings.normal.str); + expect(res).toEqual(strings.normal.ta); + }); + + it('works as expected', () => { + const res = encodeTa(strings.tricky.str); + expect(res).toEqual(strings.tricky.ta); + }); + }); + + describe('decodeTa', () => { + it('decodes symbols', () => { + const res = decodeTa(strings.symbols.ta); + expect(res).toEqual(strings.symbols.str); + }); + + it('decodes spaces', () => { + const res = decodeTa(strings.spaces.ta); + expect(res).toEqual(strings.spaces.str); + }); + + it('decodes sigs', () => { + const res = decodeTa(strings.sigs.ta); + expect(res).toEqual(strings.sigs.str); + }); + + it('decodes periods', () => { + const res = decodeTa(strings.periods.ta); + expect(res).toEqual(strings.periods.str); + }); + + it('decodes uppercase characters', () => { + const res = decodeTa(strings.uppercase.ta); + expect(res).toEqual(strings.uppercase.str); + }); + + it("doesn't decode digits, lowercase, or dashes", () => { + const res = decodeTa(strings.normal.ta); + expect(res).toEqual(strings.normal.str); + }); + + it('works as expected', () => { + const res = decodeTa(strings.tricky.ta); + expect(res).toEqual(strings.tricky.str); + }); + }); +}); + const UD_PAIRS: [string, BigInteger][] = [ ['123', bigInt(123)], ['7.827.527.286', bigInt(7827527286)],