Using Json in Reason with Belt

interop
bsb

#1

I’ve got this repo where im testing converting some json with Belt.

Demo.re Error

  • Running Demo.re I get output where list length is 71 but logging only shows two items. Why?:
length using list length:  71
[ { name: 'Image',
    type: 'img',
    props:
     { src: 'https://c8r.imgix.net/120f3501b903b57b3b5ec654/60.jpg',
       w: 1 },
    style:
     { display: '${props.inline? \'inline\': \'block\'}',
       maxWidth: '100%' },
    examples:
     [ '<Image mb={3} />',
       '<Image src=\'https://c8r.imgix.net/4edc08e4bc121c4ecadfca68/12.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/87be409330dcb961fa548cb6/7.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/2a32c3132c544295ba531c19/6.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/9828c73fa60db50a76e7146c/5.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/2466f8f593c33a7fed01944a/2.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/144e345e22a23dbb1c79444b/11.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/4edc08e4bc121c4ecadfca68/12.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/d0d9307256e31e890b8bf867/13.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/2621cd3d6e685b470e9b298e/14.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/c91d73af39fc0812cc14e621/15.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/11f9e385c3dc98b892c1f79f/16.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/2d22d6d08b89fb89ba41aed2/17.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/b97f1bd4082879190414455f/18.jpg?w=1920\' />',
       '<Image src=\'https://c8r.imgix.net/ed2e3510a8b21dd165b74efb/19.jpg?w=1920\' />' ],
    system: [],
    description: 'Block level image. Fills parent container. Can work in Cards or Panels.' },
  [ { name: 'NavLink',
      type: 'a',
      props: [Object],
      style: [Object],
      examples: [Array],
      system: [Array],
      keywords: [Array] },
    [ [Object], [Array] ] ] ]

ComponentDecode.re

  • What is the relationship between Json.Decode a Belt.list type. Getting this error ComponentDecode.re
  We've found a bug for you!
  /Users/prisc_000/code/BHYV/lab2record/src/ComponentDecode.re 68:15-30

  66 │   json |> Json.Decode.list(decodeComponent);
  67 │
  68 │ components |> decodeComponents |> Js.log;

  This has type:
    Js.Json.t => Lab2record.Types.components
  But somewhere wanted:
    Belt.List.t('a) => 'b

  The incompatible parts:
    Js.Json.t (defined as Js.Json.t)
    vs
    Belt.List.t('a) (defined as list('a))

ninja: build stopped: subcommand failed.

Thanks for any guidance.


#2

You need to pass a Js.Json.t type to the function, not a list


#3

In Demo.re or ComponentDecode.re?


#4

With regards to your first issue in Demo.re:

Running Demo.re I get output where list length is 71 but logging only shows two items. Why?:

I don’t think your issue is with Belt, I think it’s with how Js.log deals with a Belt list. It looks like Js.log can only log out nested values to a certain level deep.

Bear with me. If I add the nestedObject and nestedArray fields to your original lab.json file, i.e:

{
  “name”: “lab-portfolio-kit”,
  “library”: “fela”,
  “components”: [
    {
    “name”: “Image”,
    “nestedObject”: {
      “helloWorld”: “hello”,
      “nestedAgain”: { “hello”: “hello” }
      },
    “nestedArray”: [[1, 2, 3], 1, 2, 3],
    “type”: “img”,
    …etc

the Js.log only provides types rather than values for items nested beyond two levels, eg

[ { name: 'Image',
    nestedObject: { helloWorld: 'hello', nestedAgain: [Object] },
    nestedArray: [ [Array], 1, 2, 3 ],
    type: 'img',
    ...etc

This is impacting how you log your list x2 out, because it looks like Js.log is encapsulating all objects after the first item in the list, into a second list:

[ { name: 'NavLink',
      type: 'a',
      props: [Object],
      style: [Object],
      examples: [Array],
      system: [Array],
      keywords: [Array] },
    [ [Object], [Array] ] ] ]

Items from the third element of the original array onward look like they have been encapsulated again and nested into that final [ [Object], [Array] ].

But if you try accessing the third element of the Belt.List x2, and logging that out, you’ll see that the data is in the Belt list x2, which is why your length count is correct, there just seems to be an issue with logging it.

---- update

The way Js.log differs for Belt and Array is probably better illustrated with this example:

let myArray = [|1, 2, 3, 4|];

let myList = Belt.List.fromArray(myArray);

Js.log(myList);
Js.log(myArray);

Outputs in the console:

[ 1, [ 2, [ 3, [Array] ] ] ]
[ 1, 2, 3, 4 ]

#5

To log out each element of the list x2, you could use:

Belt.List.forEach(x2, x => Js.log(x));

But there’s probably a better way to approach. :woman_shrugging:t3:


#6

@keira very super useful info right there. where did you find that? What part of the what docs? if you dont mind.

Might as well make this a Belt for dummies post. Other questions I spent too much time on.

What does MapWithIndex look like on that same array I cant seem to get the syntax right or find an example of it? This is what I have hacked together Inspired by gradus-reason.com construct-a-map-from-a-list but I I can figure out how to use find on it to search by a name and return the whole component.

module StringMap = Map.Make(String);

let myList = Belt.List.ofArray(components);

/* List.length(myList) |> Js.log; */
let getComponentMap = myList =>
  List.fold_left(
    (map, component) => StringMap.add(component.name, component, map),
    StringMap.empty,
    myList,
  );

let componentMap = getComponentMap(myList);

#7

Hey @idkjs

Sooo - I didn’t find this behaviour with Js.log nesting discussed in the docs (although it could be there) - but I had some time today so played with your repo while looking at https://bucklescript.github.io/bucklescript/api/Belt.List.html, because I’m also trying to get to know the Belt module better :slight_smile:

(I’m going to love it when there are a bunch more examples and blog posts out there in a few months)

The nesting with lists is something to do with a List being a singly linked list, so it’s represented differently to an Array. Anyone reading this - feel free to jump in with a more comprehensive explanation!

Re your StringMap example, I think your main issue was you were trying to use JavaScript Object / Reason record syntax on component.name. Also, ofArray is deprecated, so have replaced with fromArray.

Try this (assuming it is in the same repo as the Demo.re module and you still have lab##components assigned to the x let binding):

module StringMap = Map.Make(String);

let myList = Belt.List.fromArray(Demo.x);

/* List.length(myList) |> Js.log; */
let getComponentMap = myList =>
  List.fold_left(
    (map, component) => StringMap.add(component##name, component, map),
    StringMap.empty,
    myList,
  );

let componentMap = getComponentMap(myList);

/* Js.log(componentMap); */
Js.log("iterate through & print the composers:");

Js.log("--------------------------------------");

componentMap
|> StringMap.iter((name, component) =>
     Js.log({j|key:$name, val:$component|j})
   );

Js.log("                       ");

Js.log("Find a particular item:");

Js.log("-----------------------");

Js.log(StringMap.find("Image", componentMap));

#8

That is awesome. Beautiful. So do we have reason records at this point or objects?

Just to mess around changed x to let x = lab##components |> Js.Array.map(Json.Encode.string);

Which breaks your code above:

We've found a bug for you!
  /Users/prisc_000/Downloads/lab2record-chat/src/DemoMap.re 13:36-41

  11 │   );
  12 │
  13 │ let componentMap = getComponentMap(myList);
  14 │
  15 │ /* Js.log(componentMap); */

  This has type:
    Belt.List.t(Js.Json.t) (defined as list(Js.Json.t))
  But somewhere wanted:
    list(Js.t(({.. name: StringMap.key} as 'a)))

  The incompatible parts:
    Js.Json.t (defined as Js.Json.t)
    vs
    Js.t('a)

ninja: build stopped: subcommand failed.

What’s your thought process when you see that?
Full disclosure, i’m fully picking your brain to learn and maybe give you an opportunity to learn too. Don’t take it the wrong way. Your way of thinking is super helpful.

Thank you.

Totally agree on the examples thing. If we have the questions, others will too so lets do it here is my thought.

As fro fromArray, depending on which project im in, it tells me fromArray or ofArray. Figuring it will all get caught up eventually. Im totally loving being in on this so early.


#9

@keira logging info here too https://reasonml.chat/t/logging-reason-values/366/2?u=idkjs


#10

Update: new repo with some reason-react to show results.

I wrote some working Polymorphic variants but don’t quite know what to do with it or its right.


#11

Read this first https://www.kylegoggin.com/sharing-types-in-a-reasonml-graphql-app/