[ANN] rescript-struct sweet v4.1 release

What’s New

S.catch

(S.t<'value>, S.catchCtx => 'value) => S.t<'value>

Use S.catch to provide a “catch value” to be returned instead of a parsing error.

let struct = S.float()->S.catch(_ => 42.)

%raw(`5`)->S.parseWith(struct)
// Ok(5.)
%raw(`"tuna"`)->S.parseWith(struct)
// Ok(42.)

Also, the callback S.catch receives a catch context as a first argument. It contains the caught error and the initial data provided to the parse function.

let struct = S.float()->S.catch(ctx => {
  Console.log(ctx.error) // The caught error
  Console.log(ctx.input) // The data provided to the parse function
  42.
})

Conceptually, this is how rescript-struct processes “catch values”:

  1. The data is parsed using the base struct
  2. If the parsing fails, the “catch value” is returned

S.jsonable

() => S.t<Js.Json.t>

let struct = S.jsonable()

%raw(`"123"`)->S.parseWith(struct)
// Ok(Js.Json.string("123"))

The jsonable struct represents a data that is compatible with JSON.

S.variant

(S.t<'value>, 'value => 'variant) => S.t<'variant>

type shape = Circle({radius: float}) | Square({x: float}) | Triangle({x: float, y: float})

// It will have the S.t<shape> type
let struct = S.float()->S.variant(radius => Circle({radius: radius}))

%raw(`1`)->S.parseWith(struct)
// Ok(Circle({radius: 1.}))

The same struct also works for serializing:

Circle({radius: 1})->S.serializeWith(struct)
// Ok(%raw(`1`))

S.list

S.t<'value> => S.t<list<'value>>

let struct = S.list(S.string())

%raw(`["Hello", "World"]`)->S.parseWith(struct)
// Ok(list{"Hello", "World"})

The list struct represents an array of data of a specific type which is transformed to ReScript’s list data structure.

ISO datetimes

The S.string()->S.String.datetime() function has following UTC validation: no timezone offsets with arbitrary sub-second decimal precision.

let datetimeStruct = S.string()->S.String.datetime()
// The datetimeStruct has the type S.t<Date.t>
// String is transformed to the Date.t instance

%raw(`"2020-01-01T00:00:00Z"`)->S.parseWith(datetimeStruct) // pass
%raw(`"2020-01-01T00:00:00.123Z"`)->S.parseWith(datetimeStruct) // pass
%raw(`"2020-01-01T00:00:00.123456Z"`)->S.parseWith(datetimeStruct) // pass (arbitrary precision)
%raw(`"2020-01-01T00:00:00+02:00"`)->S.parseWith(datetimeStruct) // fail (no offsets allowed)

Other improvements

  • Updated build step of the package:
    • Now it’s published with both .bs.js and .bs.mjs precompiled. You can depend on them without the need to run the compiler.
    • The JS-friendly API now depends on the compiled .bs.mjs/.bs.js files, preventing the duplication of the code in the bundle.
    • Improved size and tree-shaking of the JS-friendly API bundle.
  • Improved readability and size of the code generated by S.inline.
  • The S.advancedTransform and S.advancedPreprocess now can accept Noop transformation.
  • Fixed S.serializeWith for recursive structs.
  • Update regex for the S.String.email built-in refinement.

Full Changelog: Comparing v4.0.0...v4.1.0 · DZakh/rescript-struct · GitHub

6 Likes