import { describe, it, expect } from 'vitest'; import { GenericEmbedded, stringify, fromJS, parse, EncodableDictionary, KeyedDictionary } from '@preserves/core'; import { SchemaInterpreter, readSchema } from '../src/index'; import './test-utils'; describe('interpreter', () => { const I = new SchemaInterpreter(); const X_schema = readSchema(` version 1 . A = . B = . C = . N = int . U = / . V = / . W = / . D1 = { symbol:A ...:... } . D2 = { any:A ...:... } . D3 = { string:A ...:... } . J = { "jsonrpc": "2.0", "id": int } . `); const X = Symbol.for('X'); I.env.set([X], X_schema); const E = I.moduleTree(); it('basically works', () => { const a = E.X.A(); const b = E.X.B(22); const c = E.X.C({v: 33, w: 44}); const n = E.X.N(22); expect(stringify(a)).toBe(''); expect(stringify(b)).toBe(''); expect(stringify(c)).toBe(''); expect(stringify(n)).toBe('22'); expect(parse('')).isPreserves(fromJS(a)); expect(parse('')).isPreserves(fromJS(b)); expect(parse('')).isPreserves(fromJS(c)); expect(parse('22')).isPreserves(fromJS(n)); expect(stringify(E.X.asA(fromJS(a)))).toBe(''); expect(stringify(E.X.asB(fromJS(b)))).toBe(''); expect(stringify(E.X.asC(fromJS(c)))).toBe(''); expect(stringify(E.X.asN(fromJS(n)))).toBe('22'); }); it('escapes JS keywords', () => { expect(Object.keys(E.X.U)).toEqual(['$class', '$true']); expect(Object.keys(E.X.V)).toEqual(['$public', '$private']); expect(Object.keys(E.X.W)).toEqual(['$const', '$let']); }); const STANDARD_METHODS = ['__as_preserve__', '__preserve_on__', '__preserve_text_on__']; it('accepts correct arguments to n-ary variant ctors', () => { expect(stringify(E.X.U.$class({ a: 123, b: 234 }))).toBe(''); expect(stringify(E.X.U.$true({ c: 123, d: 234 }))).toBe(''); expect(Object.keys(E.X.U.$class({ a: 123, b: 234 }))).toEqual([ '_variant', 'a', 'b', ... STANDARD_METHODS]); }); it('accepts correct arguments to unary variant ctors', () => { expect(stringify(E.X.V.$public(123))).toBe(''); expect(stringify(E.X.V.$private(123))).toBe(''); expect(Object.keys(E.X.V.$public(123))).toEqual([ '_variant', 'n', ... STANDARD_METHODS]); }); it('accepts correct arguments to nullary variant ctors', () => { expect(stringify(E.X.W.$const())).toBe(''); expect(stringify(E.X.W.$let())).toBe(''); expect(Object.keys(E.X.W.$const())).toEqual([ '_variant', ... STANDARD_METHODS]); }); it('produces JsDictionary for symbol-keyed dicts', () => { const v = E.X.asD1(parse('{ a: , b: }')); expect(Object.keys(v)).toEqual(['a', 'b']); expect(stringify(E.X.fromA(v.a))).toBe(''); expect(stringify(E.X.fromA(v.b))).toBe(''); }); it('produces EncodableDictionary for any-keyed dicts', () => { const d2 = E.X.asD2(parse('{ a: , b: }')); expect(d2 instanceof EncodableDictionary).toBe(true); expect(Array.from(d2.keys())).toEqual([Symbol.for('a'), Symbol.for('b')]); expect(fromJS(d2.get(Symbol.for('a')))).isPreserves(fromJS(E.X.A())); }); it('accepts either kind of dictionary for symbol-keyed dicts', () => { const v = { a: E.X.A(), b: E.X.A() }; expect(stringify(v)).toBe('{a: b: }'); expect(E.X.fromD1(v)).isPreserves(parse('{a: b: }')); expect(E.X.fromD1(E.X.D1(v))).isPreserves(parse('{a: b: }')); expect(E.X.fromD1(E.X.D1(new KeyedDictionary([ [parse('a'), parse('')], [parse('b'), parse('')], ])))).isPreserves(parse('{a: b: }')); }); it('accepts either kind of dictionary for any-keyed dicts', () => { const v = { a: E.X.A(), b: E.X.A() }; expect(stringify(v)).toBe('{a: b: }'); expect(E.X.fromD2(v)).isPreserves(parse('{a: b: }')); expect(E.X.fromD2(E.X.D2(v))).isPreserves(parse('{a: b: }')); expect(E.X.fromD2(E.X.D2(new KeyedDictionary([ [parse('a'), parse('')], [parse('b'), parse('')], ])))).isPreserves(parse('{a: b: }')); }); it('only includes fields that have useful information', () => { const v = E.X.asJ(parse('{"jsonrpc": "2.0", "id": 123}')); expect('id' in v).toBe(true); expect(v.id).toBe(123); expect('jsonrpc' in v).toBe(false); }); });