Skip to content

Commit 8a8e7d0

Browse files
committed
Use built-in JSON String transformation for JSON String output in S.compile
1 parent 48bf2f7 commit 8a8e7d0

File tree

4 files changed

+104
-104
lines changed

4 files changed

+104
-104
lines changed

IDEAS.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# Ideas draft
22

3-
## Alpha.3
3+
## Alpha.4
44

5-
- `S.unknown.with(S.to, S.schema(true).with(S.noValidation, true))` - Support transformation to literals without validation, to be able to set the output value. (This is how assert works)
6-
- Use ReScript v12
7-
- Use unboxed variants for JSONSchema definitions and dependencies
5+
- Use built-in JSON String transformation for JSON String output in `S.compile`
86

97
## v11
108

packages/sury/src/Sury.res

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,8 @@ let failTransform = (b, ~inputVar, ~path, ~target) => {
16691669

16701670
let jsonName = `JSON`
16711671

1672+
let jsonString = shaken("jsonString")
1673+
16721674
let inputToString = (b, input: val) => {
16731675
b->B.val(`""+${input.inline}`, ~schema=string)
16741676
}
@@ -1968,6 +1970,12 @@ and internalCompile = (~schema, ~flag, ~defs) => {
19681970
mut.to = Some(t)
19691971
})
19701972
->castToInternal
1973+
} else if flag->Flag.unsafeHas(Flag.jsonStringOutput) {
1974+
schema
1975+
->updateOutput(mut => {
1976+
mut.to = Some(jsonString)
1977+
})
1978+
->castToInternal
19711979
} else {
19721980
schema
19731981
}
@@ -1979,17 +1987,10 @@ and internalCompile = (~schema, ~flag, ~defs) => {
19791987
let isAsync = output.flag->Flag.has(ValFlag.async)
19801988
schema.isAsync = Some(isAsync)
19811989

1982-
if (
1983-
code === "" &&
1984-
output === input &&
1985-
!(flag->Flag.unsafeHas(Flag.async->Flag.with(Flag.jsonStringOutput)))
1986-
) {
1990+
if code === "" && output === input && !(flag->Flag.unsafeHas(Flag.async)) {
19871991
Builder.noopOperation
19881992
} else {
19891993
let inlinedOutput = ref(output.inline)
1990-
if flag->Flag.unsafeHas(Flag.jsonStringOutput) {
1991-
inlinedOutput := `JSON.stringify(${inlinedOutput.contents})`
1992-
}
19931994
if flag->Flag.unsafeHas(Flag.async) && !isAsync && !(defs->Obj.magic) {
19941995
inlinedOutput := `Promise.resolve(${inlinedOutput.contents})`
19951996
}
@@ -3556,8 +3557,6 @@ let enableJson = () => {
35563557
}
35573558
}
35583559

3559-
let jsonString = shaken("jsonString")
3560-
35613560
let enableJsonString = {
35623561
let inlineJsonString = (b, ~schema, ~selfSchema, ~path) => {
35633562
let tagFlag = schema.tag->TagFlag.get

packages/sury/src/Sury.res.mjs

Lines changed: 89 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,8 @@ function setHas(has, tag) {
972972

973973
let jsonName = "JSON";
974974

975+
let jsonString = shaken("jsonString");
976+
975977
function inputToString(b, input) {
976978
return val(b, "\"\"+" + input.i, string);
977979
}
@@ -1154,16 +1156,43 @@ function parse(prevB, schema, inputArg, path) {
11541156
return input;
11551157
}
11561158

1157-
function getOutputSchema(_schema) {
1158-
while (true) {
1159-
let schema = _schema;
1160-
let to = schema.to;
1161-
if (to === undefined) {
1162-
return schema;
1163-
}
1164-
_schema = to;
1165-
continue;
1159+
function internalCompile(schema, flag, defs) {
1160+
let b = rootScope(flag, defs);
1161+
if (flag & 8) {
1162+
let output = reverse(schema);
1163+
jsonableValidation(output, output, "", flag);
1164+
}
1165+
let input = {
1166+
b: b,
1167+
v: _var,
1168+
i: "i",
1169+
f: 0,
1170+
type: "unknown"
11661171
};
1172+
let schema$1 = flag & 4 ? updateOutput(schema, mut => {
1173+
let t = new Schema(unit.type);
1174+
t.const = unit.const;
1175+
t.noValidation = true;
1176+
mut.to = t;
1177+
}) : (
1178+
flag & 16 ? updateOutput(schema, mut => {
1179+
mut.to = jsonString;
1180+
}) : schema
1181+
);
1182+
let output$1 = parse(b, schema$1, input, "");
1183+
let code = allocateScope(b);
1184+
let isAsync = has(output$1.f, 2);
1185+
schema$1.isAsync = isAsync;
1186+
if (code === "" && output$1 === input && !(flag & 2)) {
1187+
return noopOperation;
1188+
}
1189+
let inlinedOutput = output$1.i;
1190+
if (flag & 2 && !isAsync && !defs) {
1191+
inlinedOutput = "Promise.resolve(" + inlinedOutput + ")";
1192+
}
1193+
let inlinedFunction = "i=>{" + code + "return " + inlinedOutput + "}";
1194+
let ctxVarValue1 = b.g.e;
1195+
return new Function("e", "s", "return " + inlinedFunction)(ctxVarValue1, s);
11671196
}
11681197

11691198
function reverse(schema) {
@@ -1291,6 +1320,18 @@ function jsonableValidation(output, parent, path, flag) {
12911320
output.items.forEach(item => jsonableValidation(item.schema, output, path + ("[" + fromString(item.location) + "]"), flag));
12921321
}
12931322

1323+
function getOutputSchema(_schema) {
1324+
while (true) {
1325+
let schema = _schema;
1326+
let to = schema.to;
1327+
if (to === undefined) {
1328+
return schema;
1329+
}
1330+
_schema = to;
1331+
continue;
1332+
};
1333+
}
1334+
12941335
function isAsyncInternal(schema, defs) {
12951336
try {
12961337
let b = rootScope(2, defs);
@@ -1311,44 +1352,6 @@ function isAsyncInternal(schema, defs) {
13111352
}
13121353
}
13131354

1314-
function internalCompile(schema, flag, defs) {
1315-
let b = rootScope(flag, defs);
1316-
if (flag & 8) {
1317-
let output = reverse(schema);
1318-
jsonableValidation(output, output, "", flag);
1319-
}
1320-
let input = {
1321-
b: b,
1322-
v: _var,
1323-
i: "i",
1324-
f: 0,
1325-
type: "unknown"
1326-
};
1327-
let schema$1 = flag & 4 ? updateOutput(schema, mut => {
1328-
let t = new Schema(unit.type);
1329-
t.const = unit.const;
1330-
t.noValidation = true;
1331-
mut.to = t;
1332-
}) : schema;
1333-
let output$1 = parse(b, schema$1, input, "");
1334-
let code = allocateScope(b);
1335-
let isAsync = has(output$1.f, 2);
1336-
schema$1.isAsync = isAsync;
1337-
if (code === "" && output$1 === input && !(flag & 18)) {
1338-
return noopOperation;
1339-
}
1340-
let inlinedOutput = output$1.i;
1341-
if (flag & 16) {
1342-
inlinedOutput = "JSON.stringify(" + inlinedOutput + ")";
1343-
}
1344-
if (flag & 2 && !isAsync && !defs) {
1345-
inlinedOutput = "Promise.resolve(" + inlinedOutput + ")";
1346-
}
1347-
let inlinedFunction = "i=>{" + code + "return " + inlinedOutput + "}";
1348-
let ctxVarValue1 = b.g.e;
1349-
return new Function("e", "s", "return " + inlinedFunction)(ctxVarValue1, s);
1350-
}
1351-
13521355
function operationFn(s, o) {
13531356
if ((o in s)) {
13541357
return (s[o]);
@@ -2371,8 +2374,6 @@ function enableJson() {
23712374
json.$defs = defs;
23722375
}
23732376

2374-
let jsonString = shaken("jsonString");
2375-
23762377
function inlineJsonString(b, schema, selfSchema, path) {
23772378
let tagFlag = flags[schema.type];
23782379
let $$const = schema.const;
@@ -2859,6 +2860,45 @@ function nested(fieldName) {
28592860
return ctx$1;
28602861
}
28612862

2863+
function advancedBuilder(definition, flattened) {
2864+
return (b, input, selfSchema, path) => {
2865+
let isFlatten = b.g.o & 64;
2866+
let outputs = isFlatten ? input.properties : ({});
2867+
if (!isFlatten) {
2868+
let items = selfSchema.items;
2869+
for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
2870+
let match = items[idx];
2871+
let location = match.location;
2872+
let itemInput = get(b, input, location);
2873+
let inlinedLocation = inlineLocation(b, location);
2874+
let path$1 = path + ("[" + inlinedLocation + "]");
2875+
outputs[location] = parse(b, match.schema, itemInput, path$1);
2876+
}
2877+
objectStrictModeCheck(b, input, items, selfSchema, path);
2878+
}
2879+
if (flattened !== undefined) {
2880+
let prevFlag = b.g.o;
2881+
b.g.o = prevFlag | 64;
2882+
for (let idx$1 = 0, idx_finish$1 = flattened.length; idx$1 < idx_finish$1; ++idx$1) {
2883+
let item = flattened[idx$1];
2884+
outputs[item.i] = parse(b, item.schema, input, path);
2885+
}
2886+
b.g.o = prevFlag;
2887+
}
2888+
let getItemOutput = item => {
2889+
switch (item.k) {
2890+
case 0 :
2891+
return outputs[item.location];
2892+
case 1 :
2893+
return get(b, getItemOutput(item.of), item.location);
2894+
case 2 :
2895+
return outputs[item.i];
2896+
}
2897+
};
2898+
return definitionToOutput(b, definition, getItemOutput, selfSchema.to);
2899+
};
2900+
}
2901+
28622902
function definitionToTarget(definition, to, flattened) {
28632903
let ritemsByItemPath = {};
28642904
let ritem = definitionToRitem(definition, "", ritemsByItemPath);
@@ -2949,45 +2989,6 @@ function definitionToTarget(definition, to, flattened) {
29492989
return mut;
29502990
}
29512991

2952-
function advancedBuilder(definition, flattened) {
2953-
return (b, input, selfSchema, path) => {
2954-
let isFlatten = b.g.o & 64;
2955-
let outputs = isFlatten ? input.properties : ({});
2956-
if (!isFlatten) {
2957-
let items = selfSchema.items;
2958-
for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
2959-
let match = items[idx];
2960-
let location = match.location;
2961-
let itemInput = get(b, input, location);
2962-
let inlinedLocation = inlineLocation(b, location);
2963-
let path$1 = path + ("[" + inlinedLocation + "]");
2964-
outputs[location] = parse(b, match.schema, itemInput, path$1);
2965-
}
2966-
objectStrictModeCheck(b, input, items, selfSchema, path);
2967-
}
2968-
if (flattened !== undefined) {
2969-
let prevFlag = b.g.o;
2970-
b.g.o = prevFlag | 64;
2971-
for (let idx$1 = 0, idx_finish$1 = flattened.length; idx$1 < idx_finish$1; ++idx$1) {
2972-
let item = flattened[idx$1];
2973-
outputs[item.i] = parse(b, item.schema, input, path);
2974-
}
2975-
b.g.o = prevFlag;
2976-
}
2977-
let getItemOutput = item => {
2978-
switch (item.k) {
2979-
case 0 :
2980-
return outputs[item.location];
2981-
case 1 :
2982-
return get(b, getItemOutput(item.of), item.location);
2983-
case 2 :
2984-
return outputs[item.i];
2985-
}
2986-
};
2987-
return definitionToOutput(b, definition, getItemOutput, selfSchema.to);
2988-
};
2989-
}
2990-
29912992
function shape(schema, definer) {
29922993
return updateOutput(schema, mut => {
29932994
let ditem = {

packages/sury/tests/S_compile_test.res

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
open Ava
22

3+
S.enableJsonString()
4+
35
let assertCode = (t, fn: 'a => 'b, code) => {
46
t->Assert.is((fn->Obj.magic)["toString"](), code)
57
}
@@ -17,9 +19,9 @@ test("Doesn't compile primitive unknown with assert output to noop", t => {
1719
})
1820

1921
test("Doesn't compile to noop when primitive converted to json string", t => {
20-
let schema = S.string
22+
let schema = S.bool
2123
let fn = schema->S.compile(~input=Any, ~output=JsonString, ~mode=Sync, ~typeValidation=false)
22-
t->assertCode(fn, `i=>{return JSON.stringify(i)}`)
24+
t->assertCode(fn, `i=>{return ""+i}`)
2325
})
2426

2527
test("JsonString output with Async mode", t => {

0 commit comments

Comments
 (0)