Record/Module generate through JSON but aware of it during build time?

Hey, so I’m currently building two projects with rescript: one “cli generator” and a “core project”.

The first one parse a json with some options, in order to have a specific ProjectDescription record (potentially a module in the future), which describe what is needed.

The second one should have access to the previously specific ProjectDescription and build according to this (with pattern matching optimization, and so on…). I want it to know about this record/module during build time.

So my first though was to generate a res file from my generator,and add the path to it in my bsconfig.json. For that, I though I will need to have a way to print a record or a module “the rescript way”, that’s why I ask this here: Print full module/record in console? - #3 by kk3

But I’m not sure if I was clear enough, or if an another and simpler way exist to achieve what I’m looking for…

I think it would be simpler to break it up like this:

  1. CLI generator parses command line options and writes JSON file describing ProjectDescription
  2. Core project reads ProjectDescription JSON file, decodes it into a ReScript record, and generates the project.

The two components can share a common projectDescription type and JSON encoder/decoder functions, making the data transfer more reliable.

2 Likes

Sure, I can do that, in a more common way as you describe. With my approach, I target the rescript optimization with dead code.

Also, the JSON file will be huge and can’t really be generate through the cli in a sane way.

It’s more reliable that you think as the cli and core share the same record, even if I’m agree it’s a bit hacky. My main concern is about how can I write this record without building a res by hand and abusing of string.

@Hongbo isn’t possible to print the equivalent of chrome debug on a CLI ? Lire pretty-printing record ? Can also be useful for debugging without chrome, in the case the code doesn’t involve front stuff

I might not be understanding the question, but here’s my understanding of what you’re describing.

I’m assuming the .json file already exists. In this example I’ll swap that to a .js file, but the same idea would apply to a .json file.

Suppose you have a file project-description.js with content:

export default {
  name: "The Project",
};

In a ReScript file ProjectDescription.res you could load this as:

@module("./project-description.js")
external data: {..} = "default"

Suppose you wanted to parse this into a type such as:

type env = Dev | Prod

type t = {
  name: string,
  env: env,
}

You could do something like this:

let get = (): t => {
  let name = switch data["name"] {
  | None => "Unknown"
  | Some(name) => name
  }

  let env = switch data["env"] {
  | None => Dev
  | Some(value) => switch value {
    | "prod" => Prod
    | _ => Dev
    }
  }

  {
    name: name,
    env: env,
  }
}

Would that help with the first part of your project?

Hum, cool idea. Does the t variable will be define during build time ?
I didn’t try yet, but I need the t type to be defined during build time, as we want to take advantage of the rescript compiler (e.g: switch optimization if only one case is possible).
If it does, I can considered it given that it make things simpler, even if I would prefer to not have to parse my json to record during runtime.

Could you explain a bit more about this?

sure, here is a dumb example to illustrate: https://rescript-lang.org/try?code=C4TwDgpgBAJgrgWwEZQLxQD5QGIHtcAUAzsAE4CWAdgOYA0UJFNAlJlAEICGpBVw9fZgCghAUlFgKAN07AIBEUID0SgDYRgUTQC5YiFOjyEARAAsIq1bmP1jAd1ylVMY8PWade5Gg7cCAFnoAJmEhIjtyYABjUy0oAG8hLCNiAEZ6IhC0AD4oACkiADorajSoAGpyhhChNi4ecnSocizUXILi3FLGiuaagF8RZiA

As you can see, as the t is already set, the switch statement is directly replace in the output. You can try to comment/uncomment the other t definition to check that.

If t is not define and the switch is wrap into a function, this optimization can’t be done as both variant are possible. It’s probably not that impressive like this, but imagine on bigger record, with function call from different files, and so on… it allow use to keep a clean and clear code on the rescript side and a light code on js side. That’s one reason (joke apart) we want to use rescript for this project.

1 Like

Thanks for explaining.

Hypothetically, suppose you have a ProjectDescription.res file that has been generated.

Are you hoping to achieve:

[1] The optimizations will happen inside the ProjectDescription.res code,

or

[2] The optimizations will happen inside code that uses ProjectDescription.res?

I suspect the optimizations you in your example will only happen in case [1]. Not sure, but from what I’ve seen that may be the case. Would that suit your case if the optimizations you described only occurred within the Project Description file.

Couple of thoughts:

[A] Could you write your project description file in ReScript? Does it need to be JSON?

[B] From a practical point of view, I wonder if the effort to achieve this is worth the benefits gained? Maybe it is for your case, but something to consider.

1 Like

I hope for [2] first, but if only [1] work I will try with function as variable or something. Not sure yet.

[A]: I will do that first anyway, but it would be more convenient to manage several projects through JSON file(s). It’s a must have, all of this is theoretical for now.

[B]: It will as the project grow and different variants will describe different behavior, more and more… Again, that’s just a game of though now, not a priority in real world. But you got a point, it will need extra work to make sure it’s optimized. It doesn’t suit every cases.

Here is another example that I try to optimized even more (even if it’s not a big deal, just for the sake of having the cleaner js code), if you have any recommendation for that: https://rescript-lang.org/try?code=C4TwDgpgBAJgrgWwEYQE5QLxQD5QJIB2wAFAJZEA0U5wAlDlAMrCrkDmxAzi+1d6wTa0AUKEixEKVACUInTA0Ika9XMwEd+7EWOgAzOAQDGAHgDkAQwB8C4paqX6GG5eHCApO7CsAbheAQxG4AAuQANuQQwmEQwBLIAGKGRrZ+YVAAXPFS9FnwyGiy8s5QnADupMBGABZQaVAA3sJQDOrsXACMfABMTjZtgp1QANTDpb3NikRkXdS9mDZKMyNz9JMAvm4xcXF5kmgKAxwARNUQYWEA9sdUx2WXqGEwxyIA9K-bULvZB1hLACxUCbRWJfboKfJIJLGYh0NzvWCXOQEMxxe6oADWUAs8jwUAgAA9IEYAjAqBYCCBscAeEg4AEvpcoGcwmAoBVgLVOf4oAB+YTvABSnAAdFcOMBgQiLGEEJduHwLAhoABHOByYCkS4EcmU6m0+nQB5QS6cg5lCxU4BMgBWcG4JvpYHpUGORm1nEuMTFlxOLKu6KeL2OLWE5UqNTBjUmah4g34fSgwp9mhYIhauCWpETyfFZBEm2EtCAA

1 Like

Good luck in your investigation.

Regarding the questions in your example code. You might have seen @unboxed?

For example:

type str2 = Str2(string, string)
@unboxed type str1 = Str1(string)

%%private(
  @inline let f = (Str2(s1, s2)) => Str1(s1 ++ s2)

  let t1 = Str2("hello", "world")
  let t2 = f(t1)

  Js.log(t2)
)

Produces:

var t2 = "helloworld";
console.log(t2);
1 Like

Pretty !
I though about it but I was lazy to try another solution with a function and not having success, thank you ! :slight_smile: