diff --git a/packages/tests/src/core/S_literal_Array_test.res b/packages/tests/src/core/S_literal_Array_test.res index fe0d7f55..f770e6df 100644 --- a/packages/tests/src/core/S_literal_Array_test.res +++ b/packages/tests/src/core/S_literal_Array_test.res @@ -111,3 +111,86 @@ module Common = { t->U.assertReverseParsesBack(schema, ("bar", true)) }) } + +module EmptyArray = { + let value: array = [] + let invalid = ["abc"] + let factory = () => S.literal([]) + + test("Successfully parses empty array literal schema", t => { + let schema = factory() + + t->Assert.deepEqual(value->S.parseAnyWith(schema), Ok(value), ()) + }) + + test("Fails to parse empty array literal schema with invalid type", t => { + let schema = factory() + + t->U.assertErrorResult( + invalid->S.parseAnyWith(schema), + { + code: InvalidType({ + expected: S.literal([])->S.toUnknown, + received: invalid->U.castAnyToUnknown, + }), + operation: Parse, + path: S.Path.empty, + }, + ) + }) + + test("Successfully serializes empty array literal schema", t => { + let schema = factory() + + t->Assert.deepEqual(value->S.serializeToUnknownWith(schema), Ok(value->U.castAnyToUnknown), ()) + }) + + test("Fails to serialize empty array literal schema with invalid value", t => { + let schema = factory() + + t->U.assertErrorResult( + invalid->S.serializeToUnknownWith(schema), + { + code: InvalidType({ + expected: S.literal([])->S.toUnknown, + received: invalid->U.castAnyToUnknown, + }), + operation: SerializeToUnknown, + path: S.Path.empty, + }, + ) + }) + + test("Compiled parse code snapshot of empty array literal schema", t => { + let schema = factory() + + t->U.assertCompiledCode( + ~schema, + ~op=#Parse, + `i=>{if(i!==e[0]&&(!Array.isArray(i)||i.length!==0)){e[1](i)}return i}`, + ) + }) + + test("Compiled serialize code snapshot of empty array literal schema", t => { + let schema = factory() + + t->U.assertCompiledCode( + ~schema, + ~op=#Serialize, + `i=>{if(i!==e[0]&&(!Array.isArray(i)||i.length!==0)){e[1](i)}return i}`, + ) + }) + + test("Reverse empty array literal schema to self", t => { + let schema = factory() + t->Assert.is(schema->S.\"~experimantalReverse", schema->S.toUnknown, ()) + }) + + test( + "Succesfully uses reversed empty array literal schema for parsing back to initial value", + t => { + let schema = factory() + t->U.assertReverseParsesBack(schema, value) + }, + ) +} diff --git a/packages/tests/src/core/S_literal_Object_test.res b/packages/tests/src/core/S_literal_Object_test.res index b92d34d1..df56492b 100644 --- a/packages/tests/src/core/S_literal_Object_test.res +++ b/packages/tests/src/core/S_literal_Object_test.res @@ -140,3 +140,86 @@ module Common = { t->U.assertReverseParsesBack(schema, {"foo": "bar"}) }) } + +module EmptyDict = { + let value: dict = Dict.make() + let invalid = Dict.fromArray([("abc", "def")]) + let factory = () => S.literal(Dict.make()) + + test("Successfully parses empty dict literal schema", t => { + let schema = factory() + + t->Assert.deepEqual(value->S.parseAnyWith(schema), Ok(value), ()) + }) + + test("Fails to parse empty dict literal schema with invalid type", t => { + let schema = factory() + + t->U.assertErrorResult( + invalid->S.parseAnyWith(schema), + { + code: InvalidType({ + expected: S.literal(Dict.make())->S.toUnknown, + received: invalid->U.castAnyToUnknown, + }), + operation: Parse, + path: S.Path.empty, + }, + ) + }) + + test("Successfully serializes empty dict literal schema", t => { + let schema = factory() + + t->Assert.deepEqual(value->S.serializeToUnknownWith(schema), Ok(value->U.castAnyToUnknown), ()) + }) + + test("Fails to serialize empty dict literal schema with invalid value", t => { + let schema = factory() + + t->U.assertErrorResult( + invalid->S.serializeToUnknownWith(schema), + { + code: InvalidType({ + expected: S.literal(Dict.make())->S.toUnknown, + received: invalid->U.castAnyToUnknown, + }), + operation: SerializeToUnknown, + path: S.Path.empty, + }, + ) + }) + + test("Compiled parse code snapshot of empty dict literal schema", t => { + let schema = factory() + + t->U.assertCompiledCode( + ~schema, + ~op=#Parse, + `i=>{if(i!==e[0]&&(!i||i.constructor!==Object||Object.keys(i).length!==0)){e[1](i)}return i}`, + ) + }) + + test("Compiled serialize code snapshot of empty dict literal schema", t => { + let schema = factory() + + t->U.assertCompiledCode( + ~schema, + ~op=#Serialize, + `i=>{if(i!==e[0]&&(!i||i.constructor!==Object||Object.keys(i).length!==0)){e[1](i)}return i}`, + ) + }) + + test("Reverse empty dict literal schema to self", t => { + let schema = factory() + t->Assert.is(schema->S.\"~experimantalReverse", schema->S.toUnknown, ()) + }) + + test( + "Succesfully uses reversed empty dict literal schema for parsing back to initial value", + t => { + let schema = factory() + t->U.assertReverseParsesBack(schema, value) + }, + ) +} diff --git a/src/S_Core.bs.mjs b/src/S_Core.bs.mjs index 42719e94..244f4e03 100644 --- a/src/S_Core.bs.mjs +++ b/src/S_Core.bs.mjs @@ -164,16 +164,10 @@ function $$var(b, val) { return _var; } var $$var$1 = varWithoutAllocation(b); - var isValScopeActive = !val.s.a; - var activeScope = isValScopeActive ? val.s : b; var i = val.i; - var allocation = i !== undefined && isValScopeActive ? $$var$1 + "=" + i : $$var$1; - var varsAllocation = activeScope.l; - activeScope.l = varsAllocation === "" ? allocation : varsAllocation + "," + allocation; - var i$1 = val.i; - if (i$1 !== undefined && !isValScopeActive) { - b.c = b.c + ($$var$1 + "=" + i$1 + ";"); - } + var allocation = i !== undefined ? $$var$1 + "=" + i : $$var$1; + var varsAllocation = val.s.l; + val.s.l = varsAllocation === "" ? allocation : varsAllocation + "," + allocation; val.v = $$var$1; return $$var$1; } @@ -748,22 +742,26 @@ function serializeToUnknownWith(value, schema) { } } +function serializeToJsonStringOrRaiseWith(value, schema, spaceOpt) { + var space = spaceOpt !== undefined ? spaceOpt : 0; + return JSON.stringify(schema.serializeToJsonOrThrow(value), null, space); +} + function serializeToJsonStringWith(value, schema, spaceOpt) { var space = spaceOpt !== undefined ? spaceOpt : 0; - var json = serializeWith(value, schema); - if (json.TAG === "Ok") { + try { return { TAG: "Ok", - _0: JSON.stringify(json._0, null, space) + _0: serializeToJsonStringOrRaiseWith(value, schema, space) + }; + } + catch (raw_exn){ + var exn = Caml_js_exceptions.internalToOCamlException(raw_exn); + return { + TAG: "Error", + _0: getOrRethrow(exn) }; - } else { - return json; } -} - -function serializeToJsonStringOrRaiseWith(value, schema, spaceOpt) { - var space = spaceOpt !== undefined ? spaceOpt : 0; - return JSON.stringify(schema.serializeToJsonOrThrow(value), null, space); } function parseJsonStringWith(jsonString, schema) { @@ -1271,15 +1269,11 @@ function getWithDefault(schema, $$default) { })); }), schema.f, (function () { var reversed = schema.r(); - var child = reversed.t; - if (typeof child !== "object") { - return reversed; - } - if (child.TAG !== "Option") { + if (reversed.t.TAG !== "Option") { return reversed; } - var child$1 = child._0; - return makeReverseSchema(child$1.n, child$1.t, child$1.m, child$1.b, child$1.f); + var child = reversed.t._0; + return makeReverseSchema(child.n, child.t, child.m, child.b, child.f); })); } diff --git a/src/S_Core.res b/src/S_Core.res index a28cbe38..9f2e392b 100644 --- a/src/S_Core.res +++ b/src/S_Core.res @@ -493,20 +493,14 @@ module Builder = { | {_var} => _var | _ => { let var = b->varWithoutAllocation - let isValScopeActive = !val._scope.isAllocated - let activeScope = isValScopeActive ? val._scope : b let allocation = switch val._initial { - | Some(i) if isValScopeActive => `${var}=${i}` - | _ => var + | Some(i) => `${var}=${i}` + | None => var } - let varsAllocation = activeScope.varsAllocation - activeScope.varsAllocation = varsAllocation === "" + let varsAllocation = val._scope.varsAllocation + val._scope.varsAllocation = varsAllocation === "" ? allocation : varsAllocation ++ "," ++ allocation - switch val._initial { - | Some(i) if !isValScopeActive => b.code = b.code ++ `${var}=${i};` - | _ => () - } val._var = Some(var) var } @@ -1166,20 +1160,21 @@ let serializeToUnknownWith = (value, schema) => { } } +let serializeToJsonStringOrRaiseWith = (value: 'value, schema: t<'value>, ~space=0): string => { + value->serializeOrRaiseWith(schema)->Js.Json.stringifyWithSpace(space) +} + let serializeToJsonStringWith = (value: 'value, schema: t<'value>, ~space=0): result< string, error, > => { - switch value->serializeWith(schema) { - | Ok(json) => Ok(json->Js.Json.stringifyWithSpace(space)) - | Error(_) as e => e + try { + serializeToJsonStringOrRaiseWith(value, schema, ~space)->Ok + } catch { + | exn => exn->InternalError.getOrRethrow->Error } } -let serializeToJsonStringOrRaiseWith = (value: 'value, schema: t<'value>, ~space=0): string => { - value->serializeOrRaiseWith(schema)->Js.Json.stringifyWithSpace(space) -} - let parseJsonStringWith = (jsonString: string, schema: t<'value>): result<'value, error> => { switch try { jsonString->Js.Json.parseExn->Ok @@ -1853,8 +1848,8 @@ module Option = { ~maybeTypeFilter=schema.maybeTypeFilter, ~reverse=() => { let reversed = schema.reverse() - switch reversed->classify { - | Option(child) => + if reversed.tagged->unsafeGetVarianTag === "Option" { + let child = reversed.tagged->unsafeGetVariantPayload // Copy to prevent mutating of primitive's reverse function // TODO: Can be improved to copy only for primitives makeReverseSchema( @@ -1864,7 +1859,8 @@ module Option = { ~builder=child.builder, ~maybeTypeFilter=child.maybeTypeFilter, ) - | _ => reversed + } else { + reversed } }, )