Skip to content

Commit

Permalink
Make parser work for s.nested
Browse files Browse the repository at this point in the history
  • Loading branch information
DZakh committed Jun 8, 2024
1 parent 1260767 commit 1b3b54e
Show file tree
Hide file tree
Showing 8 changed files with 773 additions and 674 deletions.
2 changes: 1 addition & 1 deletion packages/tests/src/core/Example_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ test("Compiled parse code snapshot", t => {
t->U.assertCompiledCode(
~schema=filmSchema,
~op=#parse,
`i=>{if(!i||i.constructor!==Object){e[11](i)}let v0=i["Id"],v1=i["Title"],v2=i["Tags"],v6=i["Rating"],v8=i["Age"];let v7;if(typeof v0!=="number"||Number.isNaN(v0)){e[0](v0)}if(typeof v1!=="string"){e[1](v1)}if(v2!==void 0&&(!Array.isArray(v2))){e[2](v2)}if(v2!==void 0){for(let v3=0;v3<v2.length;++v3){let v5=v2[v3];try{if(typeof v5!=="string"){e[3](v5)}}catch(v4){if(v4&&v4.s===s){v4.path="[\\"Tags\\"]"+\'["\'+v3+\'"]\'+v4.path}throw v4}}}try{v6==="G"||e[5](v6);v7=v6}catch(e0){try{v6==="PG"||e[6](v6);v7=v6}catch(e1){try{v6==="PG13"||e[7](v6);v7=v6}catch(e2){try{v6==="R"||e[8](v6);v7=v6}catch(e3){e[9]([e0,e1,e2,e3,])}}}}if(v8!==void 0&&(typeof v8!=="number"||v8>2147483647||v8<-2147483648||v8%1!==0)){e[10](v8)}return {"id":v0,"title":v1,"tags":v2===void 0?e[4]:v2,"rating":v7,"deprecatedAgeRestriction":v8,}}`,
`i=>{if(!i||i.constructor!==Object){e[11](i)}let v0=i["Id"],v1=i["Title"],v2=i["Tags"],v6=i["Rating"],v7,v8=i["Age"];if(typeof v0!=="number"||Number.isNaN(v0)){e[0](v0)}if(typeof v1!=="string"){e[1](v1)}if(v2!==void 0&&(!Array.isArray(v2))){e[2](v2)}if(v2!==void 0){for(let v3=0;v3<v2.length;++v3){let v5=v2[v3];try{if(typeof v5!=="string"){e[3](v5)}}catch(v4){if(v4&&v4.s===s){v4.path="[\\"Tags\\"]"+\'["\'+v3+\'"]\'+v4.path}throw v4}}}try{v6==="G"||e[5](v6);v7=v6}catch(e0){try{v6==="PG"||e[6](v6);v7=v6}catch(e1){try{v6==="PG13"||e[7](v6);v7=v6}catch(e2){try{v6==="R"||e[8](v6);v7=v6}catch(e3){e[9]([e0,e1,e2,e3,])}}}}if(v8!==void 0&&(typeof v8!=="number"||v8>2147483647||v8<-2147483648||v8%1!==0)){e[10](v8)}return {"id":v0,"title":v1,"tags":v2===void 0?e[4]:v2,"rating":v7,"deprecatedAgeRestriction":v8,}}`,
)
})

Expand Down
145 changes: 127 additions & 18 deletions packages/tests/src/core/S_object_nested_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,44 @@ test("Fails to create schema with nested called additinally to non-object field"
)
})

test("Fails to use nested inside of another nested", t => {
t->Assert.throws(
() => {
S.object(
test("Has correct tagged type with nested inside another nested", t => {
let schema = S.object(s =>
{
"foo": s.field("foo", S.string),
"nested": s.nested(
"nested1",
s =>
{
"foo": s.field("foo", S.string),
"nested": s.nested(
"nested1",
s =>
{
"bar": s.nested("nested2", s => s.field("bar", S.string)),
},
),
"bar": s.nested("nested2", s => s.field("bar", S.string)),
},
)
},
~expectations={
message: `[rescript-schema] Nested "nested2" inside of another nested "nested1" is not supported`,
},
(),
),
}
)

t->U.unsafeAssertEqualSchemas(
schema,
S.object(s =>
{
"foo": s.field("foo", S.string),
"nested": s.field(
"nested1",
S.object(
s =>
{
"nested2": s.field(
"nested2",
S.object(
s =>
{
"bar": s.field("bar", S.string),
},
),
),
},
),
),
}
),
)
})

Expand All @@ -160,4 +177,96 @@ test("Successfully parses simple schema with nested", t => {
Ok({"foo": "foo", "bar": "bar"}),
(),
)
t->U.assertCompiledCode(
~op=#parse,
~schema,
`i=>{if(!i||i.constructor!==Object){e[3](i)}let v0=i["foo"],v1=i["nested"];if(typeof v0!=="string"){e[0](v0)}if(!v1||v1.constructor!==Object){e[1](v1)}let v2=v1["bar"];if(typeof v2!=="string"){e[2](v2)}return {"foo":v0,"bar":v2,}}`,
)
})

test("Successfully parses schema with nested called multiple times", t => {
let schema = S.object(s =>
{
"foo": s.field("foo", S.string),
"bar": s.nested("nested", s => s.field("bar", S.string)),
"baz": s.nested("nested", s => s.field("baz", S.string)),
}
)

t->Assert.deepEqual(
%raw(`{"foo": "foo", "nested": {"bar": "bar", "baz": "baz"}}`)->S.parseAnyWith(schema),
Ok({"foo": "foo", "bar": "bar", "baz": "baz"}),
(),
)
t->U.assertCompiledCode(
~op=#parse,
~schema,
`i=>{if(!i||i.constructor!==Object){e[4](i)}let v0=i["foo"],v1=i["nested"];if(typeof v0!=="string"){e[0](v0)}if(!v1||v1.constructor!==Object){e[1](v1)}let v2=v1["bar"],v3=v1["baz"];if(typeof v2!=="string"){e[2](v2)}if(typeof v3!=="string"){e[3](v3)}return {"foo":v0,"bar":v2,"baz":v3,}}`,
)
})

test("Successfully parses schema with nested inside another nested", t => {
let schema = S.object(s =>
{
"foo": s.field("foo", S.string),
"bar": s.nested("nested1", s => s.nested("nested2", s => s.field("bar", S.string))),
}
)

t->Assert.deepEqual(
%raw(`{"foo": "foo", "nested1": {"nested2": {"bar":"bar"}}}`)->S.parseAnyWith(schema),
Ok({"foo": "foo", "bar": "bar"}),
(),
)
t->U.assertCompiledCode(
~op=#parse,
~schema,
`i=>{if(!i||i.constructor!==Object){e[4](i)}let v0=i["foo"],v1=i["nested1"];if(typeof v0!=="string"){e[0](v0)}if(!v1||v1.constructor!==Object){e[1](v1)}let v2=v1["nested2"];if(!v2||v2.constructor!==Object){e[2](v2)}let v3=v2["bar"];if(typeof v3!=="string"){e[3](v3)}return {"foo":v0,"bar":v3,}}`,
)
})

test("Fails to parse nested which is not an object", t => {
let schema = S.object(s =>
{
"foo": s.field("foo", S.string),
"bar": s.nested("nested", s => s.field("bar", S.string)),
}
)

t->U.assertErrorResult(
%raw(`{"foo": "foo", "nested": "string"}`)->S.parseAnyWith(schema),
{
code: InvalidType({
expected: S.object(s =>
{
"bar": s.field("bar", S.string),
}
)->S.toUnknown,
received: %raw(`"string"`),
}),
operation: Parsing,
path: S.Path.fromLocation("nested"),
},
)
})

test("Fails to parse nested field", t => {
let schema = S.object(s =>
{
"foo": s.field("foo", S.string),
"bar": s.nested("nested", s => s.field("bar", S.string)),
}
)

t->U.assertErrorResult(
%raw(`{"foo": "foo", "nested": {"bar": 123}}`)->S.parseAnyWith(schema),
{
code: InvalidType({
expected: S.string->S.toUnknown,
received: %raw(`123`),
}),
operation: Parsing,
path: S.Path.fromArray(["nested", "bar"]),
},
)
})
12 changes: 6 additions & 6 deletions packages/tests/src/core/S_object_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ test("Object schema parsing checks order", t => {
let schema = S.object(s => {
s.tag("tag", "value")
{
"key": s.field("key", S.literal("value")),
"key": s.field("key", S.string),
}
})->S.Object.strict

Expand All @@ -937,7 +937,7 @@ test("Object schema parsing checks order", t => {
)
// Tag check should be the second
t->U.assertErrorResult(
%raw(`{tag: "wrong", key: "wrong", unknownKey: "value", unknownKey2: "value"}`)->S.parseAnyWith(
%raw(`{tag: "wrong", key: 123, unknownKey: "value", unknownKey2: "value"}`)->S.parseAnyWith(
schema,
),
{
Expand All @@ -948,11 +948,11 @@ test("Object schema parsing checks order", t => {
)
// Field check should be the third
t->U.assertErrorResult(
%raw(`{tag: "value", key: "wrong", unknownKey: "value", unknownKey2: "value"}`)->S.parseAnyWith(
%raw(`{tag: "value", key: 123, unknownKey: "value", unknownKey2: "value"}`)->S.parseAnyWith(
schema,
),
{
code: InvalidLiteral({expected: S.Literal.parse("value"), received: %raw(`"wrong"`)}),
code: InvalidType({expected: S.string->S.toUnknown, received: %raw(`123`)}),
operation: Parsing,
path: S.Path.fromLocation("key"),
},
Expand Down Expand Up @@ -1004,7 +1004,7 @@ module Compiled = {
t->U.assertCompiledCode(
~schema,
~op=#parse,
`i=>{if(!i||i.constructor!==Object){e[2](i)}let v1=i["bar"];let v0=e[0](i["foo"]);if(typeof v1!=="boolean"){e[1](v1)}return ()=>Promise.all([v0()]).then(([v0])=>({"foo":v0,"bar":v1,}))}`,
`i=>{if(!i||i.constructor!==Object){e[2](i)}let v0=e[0](i["foo"]),v1=i["bar"];if(typeof v1!=="boolean"){e[1](v1)}return ()=>Promise.all([v0()]).then(([v0])=>({"foo":v0,"bar":v1,}))}`,
)
})

Expand Down Expand Up @@ -1060,7 +1060,7 @@ module Compiled = {
t->U.assertCompiledCode(
~schema,
~op=#parse,
`i=>{if(!i||i.constructor!==Object){e[5](i)}let v0=i["tag"],v1=i["FOO"],v2=i["BAR"],v3;v0===0||e[0](v0);if(typeof v1!=="string"){e[1](v1)}if(typeof v2!=="boolean"){e[2](v2)}for(v3 in i){if(v3!=="tag"&&v3!=="FOO"&&v3!=="BAR"){e[4](v3)}}return {"foo":v1,"bar":v2,"zoo":e[3],}}`,
`i=>{if(!i||i.constructor!==Object){e[5](i)}let v0=i["tag"],v1=i["FOO"],v2=i["BAR"],v3;v0===0||e[0](v0);if(typeof v1!=="string"){e[1](v1)}if(typeof v2!=="boolean"){e[2](v2)}for(v3 in i){if(v3!=="tag"&&v3!=="FOO"&&v3!=="BAR"){e[3](v3)}}return {"foo":v1,"bar":v2,"zoo":e[4],}}`,
)
},
)
Expand Down
2 changes: 1 addition & 1 deletion packages/tests/src/core/S_tuple_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ module Compiled = {
t->U.assertCompiledCode(
~schema,
~op=#parse,
`i=>{if(!Array.isArray(i)||i.length!==2){e[2](i)}let v1=i["1"];let v0=e[0](i["0"]);if(typeof v1!=="boolean"){e[1](v1)}return ()=>Promise.all([v0()]).then(([v0])=>([v0,v1,]))}`,
`i=>{if(!Array.isArray(i)||i.length!==2){e[2](i)}let v0=e[0](i["0"]),v1=i["1"];if(typeof v1!=="boolean"){e[1](v1)}return ()=>Promise.all([v0()]).then(([v0])=>([v0,v1,]))}`,
)
})

Expand Down
4 changes: 1 addition & 3 deletions packages/tests/src/utils/U.bs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ function cleanUpSchema(schema) {
var value = param[1];
var key = param[0];
switch (key) {
case "definition" :
case "i" :
case "itemsSet" :
case "nestedCtxs" :
case "isNested" :
return ;
default:
if (typeof value === "function") {
Expand Down
4 changes: 1 addition & 3 deletions packages/tests/src/utils/U.res
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ let rec cleanUpSchema = schema => {
switch key {
| "i"
| // Object ctx
"itemsSet"
| "definition"
| "nestedCtxs" => ()
"isNested" => ()
| _ =>
if typeof(value) === #function {
()
Expand Down
Loading

0 comments on commit 1b3b54e

Please sign in to comment.