From d4a772e88b4d176042cec61b334f9a28accdc1dc Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Fri, 7 Nov 2025 19:36:22 -0800 Subject: [PATCH] json.encode & json.decode --- src/prelude/index.ts | 2 + src/prelude/json.ts | 7 +++ src/prelude/tests/json.test.ts | 84 ++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/prelude/json.ts create mode 100644 src/prelude/tests/json.test.ts diff --git a/src/prelude/index.ts b/src/prelude/index.ts index 488414b..a3966e1 100644 --- a/src/prelude/index.ts +++ b/src/prelude/index.ts @@ -6,6 +6,7 @@ import { } from 'reefvm' import { dict } from './dict' +import { json } from './json' import { load } from './load' import { list } from './list' import { math } from './math' @@ -13,6 +14,7 @@ import { str } from './str' export const globals = { dict, + json, load, list, math, diff --git a/src/prelude/json.ts b/src/prelude/json.ts new file mode 100644 index 0000000..c54a908 --- /dev/null +++ b/src/prelude/json.ts @@ -0,0 +1,7 @@ +export const json = { + encode: (s: any) => JSON.stringify(s), + decode: (s: string) => JSON.parse(s), +} + + ; (json as any).parse = json.decode + ; (json as any).stringify = json.encode \ No newline at end of file diff --git a/src/prelude/tests/json.test.ts b/src/prelude/tests/json.test.ts new file mode 100644 index 0000000..544722e --- /dev/null +++ b/src/prelude/tests/json.test.ts @@ -0,0 +1,84 @@ +import { expect, describe, test } from 'bun:test' + +describe('json', () => { + test('json.decode', () => { + expect(`json.decode '[1,2,3]'`).toEvaluateTo([1, 2, 3]) + expect(`json.decode '"heya"'`).toEvaluateTo('heya') + expect(`json.decode '[true, false, null]'`).toEvaluateTo([true, false, null]) + expect(`json.decode '{"a": true, "b": false, "c": "yeah"}'`).toEvaluateTo({ a: true, b: false, c: "yeah" }) + }) + + test('json.encode', () => { + expect(`json.encode [1 2 3]`).toEvaluateTo('[1,2,3]') + expect(`json.encode 'heya'`).toEvaluateTo('"heya"') + expect(`json.encode [true false null]`).toEvaluateTo('[true,false,null]') + expect(`json.encode [a=true b=false c='yeah'] | json.decode`).toEvaluateTo({ a: true, b: false, c: "yeah" }) + }) + + test('edge cases - empty structures', () => { + expect(`json.decode '[]'`).toEvaluateTo([]) + expect(`json.decode '{}'`).toEvaluateTo({}) + expect(`json.encode []`).toEvaluateTo('[]') + expect(`json.encode [=]`).toEvaluateTo('{}') + }) + + test('edge cases - special characters in strings', () => { + expect(`json.decode '"hello\\\\nworld"'`).toEvaluateTo('hello\nworld') + expect(`json.decode '"tab\\\\there"'`).toEvaluateTo('tab\there') + expect(`json.decode '"forward/slash"'`).toEvaluateTo('forward/slash') + expect(`json.decode '"with\\\\\\\\backslash"'`).toEvaluateTo('with\\backslash') + }) + + test('numbers - integers and floats', () => { + expect(`json.decode '42'`).toEvaluateTo(42) + expect(`json.decode '0'`).toEvaluateTo(0) + expect(`json.decode '-17'`).toEvaluateTo(-17) + expect(`json.decode '3.14159'`).toEvaluateTo(3.14159) + expect(`json.decode '-0.5'`).toEvaluateTo(-0.5) + }) + + test('numbers - scientific notation', () => { + expect(`json.decode '1e10'`).toEvaluateTo(1e10) + expect(`json.decode '2.5e-3'`).toEvaluateTo(2.5e-3) + expect(`json.decode '1.23E+5'`).toEvaluateTo(1.23e5) + }) + + test('unicode - emoji and special characters', () => { + expect(`json.decode '"hello 👋"'`).toEvaluateTo('hello 👋') + expect(`json.decode '"🎉🚀✨"'`).toEvaluateTo('🎉🚀✨') + expect(`json.encode '你好'`).toEvaluateTo('"你好"') + expect(`json.encode 'café'`).toEvaluateTo('"café"') + }) + + test('nested structures - arrays', () => { + expect(`json.decode '[[1,2],[3,4],[5,6]]'`).toEvaluateTo([[1, 2], [3, 4], [5, 6]]) + expect(`json.decode '[1,[2,[3,[4]]]]'`).toEvaluateTo([1, [2, [3, [4]]]]) + }) + + test('nested structures - objects', () => { + expect(`json.decode '{"user":{"name":"Alice","age":30}}'`).toEvaluateTo({ + user: { name: 'Alice', age: 30 } + }) + expect(`json.decode '{"a":{"b":{"c":"deep"}}}'`).toEvaluateTo({ + a: { b: { c: 'deep' } } + }) + }) + + test('nested structures - mixed arrays and objects', () => { + expect(`json.decode '[{"id":1,"tags":["a","b"]},{"id":2,"tags":["c"]}]'`).toEvaluateTo([ + { id: 1, tags: ['a', 'b'] }, + { id: 2, tags: ['c'] } + ]) + expect(`json.decode '{"items":[1,2,3],"meta":{"count":3}}'`).toEvaluateTo({ + items: [1, 2, 3], + meta: { count: 3 } + }) + }) + + test('error handling - invalid json', () => { + expect(`json.decode '{invalid}'`).toFailEvaluation() + expect(`json.decode '[1,2,3'`).toFailEvaluation() + expect(`json.decode 'undefined'`).toFailEvaluation() + expect(`json.decode ''`).toFailEvaluation() + }) +}) \ No newline at end of file -- 2.50.1