npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rescript-schema-driven

v0.0.4

Published

type-module codegenerator by schema-dsl for rescript

Downloads

2

Readme

rescript-schema-driven

serializable type modules generation for rescript with rescript-struct

Installation

npm install rescript-struct@4.*
npm install rescript-schema-driven

Note! package coded for rescript-struct v4!

Then add rescript-struct and rescript-schema-driven to bs-dependencies in your bsconfig.json:

{
  ...
+ "bs-dependencies": ["rescript-struct", "rescript-schema-driven"]
+ "bsc-flags": ["-open RescriptStruct"],
}

Motivation

  • Make your serializible types-schemas file, thats will one source-of-true.
  • Have always correct and capable types-declarations and rescript-struct schemas, and safety refactoring, they are gives to you.
  • Extends generated modules with plugins, adds to all modules new functionality you need.

Example of usage

Create file with schemas declaration code

open Belt
open! SchemaDriven

let _genDir: string = %raw(`require("path").resolve(module.path, "..", "..", "..", "_generated")`)

//Engine is code-generation runner information container which will be used 
//for generation every module
let eng =
  defEngine(
    _genDir, //target dir for generation files
    [SchemaDrivenRescriptStructPlugin.plugin], //plugins. 
    //Plugins add extra api for modules and may be used for exteding functionality
    //This plugin will add extra api:
    //let parse: Js.Json.t => result<t, exn>
    //let parseAny: 'a => result<t, exn>
    //let parseJson: string => result<t, exn>
    //let parseAsync: Js.Json.t => promise<result<t, exn>>
    //let serialize: t => result<Js.Json.t, exn>
    //let serializeToUnknown: t => result<unknown, exn>
    //let serializeToJson: t => result<string, exn>
    RemoveAllFilesFromDir, //pregeneration dir handling strategy
  )->Belt.Result.getExn

//Will generate module TestOptionInt with type option<int> and api for interaction with type
let testOptionInt = optionNull("TestOptionInt", int, eng)->Result.getExn

//Will generate module TestPerson with type
//{
//  id: int,
//  ages: option<int>
//  name: string
//} and api for interaction with type
let testPersonRec =
  record(
    "Test-Person", //Invalid module name, will automatically correct to TestPerson
    [Field("id", int), Field("ages", testOptionInt), Field("name", string)],
    eng,
  )->Result.getExn

and run it by node directly.

API

SchemaDriven.resi

open SchemaDrivenModule
open SchemaDrivenPlugin
open SchemaDrivenUnexpectedFilesStrategy

type field<'a> = SchemaDrivenHelper.field<'a>
type variant<'a> = SchemaDrivenHelper.variant<'a>

let defEngine: (
  string, //target dir path
  array<schemaDrivenPlugin>, //plugins
  unexpectedFilesStrategy, //use RemoveAllFilesFromDir by default, 
  //more details in SchemaDrivenUnexpectedFilesStrategy.resi
) => result<SchemaDrivenEngine.schemaDrivenEngine, exn>

//type schemaDrivenModule is container with wrapped info about existed module file, implements
//SchemaDrivenModule.SchemaDrivenModule module type.
//For primitive data types contains ref on pre-compiled module. For generic types 

let int: schemaDrivenModule //int type module ref

let float: schemaDrivenModule //float type module ref

let string: schemaDrivenModule //string type module ref

let bool: schemaDrivenModule //bool type module ref

let unknown: schemaDrivenModule //unknown type module ref

//module generator for option type, wich will serizlize to value or null
let optionNull: (
  string, //module name
  schemaDrivenModule,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for record type which will serialize to js-object (js-structure)
let record: (
  ~strict: bool=?,
  string, //module name
  array<field<schemaDrivenModule>>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for object type which will serialize to js-object (js-structure)
let object: (
  ~strict: bool=?,
  string, //module name
  array<field<schemaDrivenModule>>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for tuple type, wich will serialized to array [t1', t2', ...]
//Power of tuple defined by num of type in param
let tupleN: (
  string, //module name
  array<schemaDrivenModule>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for tuple, which will serialize to structure {t_0: t0', t_1: t1', ...}
let tupleObject: (
  ~strict: bool=?,
  string, //module name
  array<schemaDrivenModule>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for variant of object, which contains variant tag in one of it's properties
let variantObject: (
  ~tagName: string=?, //name of tag-contans property
  ~strict: bool=?,
  string, //module name
  array<variant<array<field<schemaDrivenModule>>>>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>
//for example declaration:
//variantObject(
//  "TestVariantObject",
//  [
//    Variant("circle", [Field("radius", float)]),
//    Variant("square", [Field("width", float), Field("height", float)]),
//  ],
//  eng,
//)
//
//will compiled to module with type 
//type testVariantObject = 
//  | Circle({
//      radius: SchemaDrivenFloat.t
//    })
//  | Square({
//      width: SchemaDrivenFloat.t,
//      height: SchemaDrivenFloat.t
//    })
//
//witch serializing to structure:
//%raw(`{TAG: "Square", width: 15.2, height: 10}`)->parse == Square({width: 15.2, height: 10.0})


//module generator for variant of oany types, which contains variant tag and constructor params
//as prroperies of object
let variantContainer: (
  ~tagName: string=?,
  ~strict: bool=?,
  string, //module name
  array<variant<array<schemaDrivenModule>>>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>
//for example declaration:
//let testVariantContainer =
//  variantContainer(
//    "TestVariantContainer",
//    [Variant("var1", [float]), Variant("var2", [testOptionStr, float]), Variant("var3", [string])],
//    eng,
//  )
//
//will compiled to module with type 
//type testVariantContainer = 
//  | Var1(SchemaDrivenFloat.t)
//  | Var2(TestOptionStr.t, SchemaDrivenFloat.t)
//  | Var3(SchemaDrivenString.t)
//
//witch serializing to structure:
//%raw(`{TAG: "Var2", t_0: null, t_1: -1}`)->parse == Var2(None, -1.0)

//Variant of parameterless constructors wich will serizlized to same strings
let variantLiteral: (
  string, //module name
  array<string>,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for array type
let array: (
  string, //module name
  schemaDrivenModule,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for list type
let list: (
  string, //module name
  schemaDrivenModule,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

//module generator for Js.Dict.t type
let dict: (
  string, //module name
  schemaDrivenModule,
  SchemaDrivenEngine.schemaDrivenEngine,
) => result<schemaDrivenModule, exn>

More examples of usage

Look more examples in this package:

  • declaration of example generated files in ./test-schema directory
  • generated example files in ./_generated directory
  • tests for then in ./_generated-test directory

Publishing

You can get the schemeDrivenModule after executing any of the functions that generate module code. However, there may be a need to access generated modules from another package to generate new modules based on them.In this case, there is a high probability that when you try to access the name of the generated module, you will restart generation and get bugs.

To avoid this, I recommend following a few simple rules:

  • Place your module in which generation is called in the dev folder, publishing only the generation result.
  • To publish links to generated modules of type schemeDrivenModule, use the publishModules function.

The publishModules function generates another file in the target folder in which the specified schemeDrivenModules will be available as data, without the risk of triggering side effects when accessed.

//Example
let eng =
  defEngine(...)->Belt.Result.getExn

let testOptionInt = optionNull("TestOptionInt", int, eng)->Result.getExn
let testOptionStr = optionNull("TestOptionStr", string, eng)->Result.getExn

...

//Will create Publish module with type aliaces to testOptionInt and testOptionStr,
let publish =
  publishModules(
    "Publish",
    [
      testOptionInt,
      testOptionStr,
      ...
    ],
    eng,
  )->Result.getExn

//--------------------------------------
//Publish.res
open SchemaDrivenModule

let testOptionInt: schemaDrivenModule = def("TestOptionInt")

let testOptionStr: schemaDrivenModule = def("TestOptionStr")
...

SchemaDrivenRescriptStructPlugin

plugin thats extends base module api. adds module type

module type ModuleType = {
  include SchemaDrivenModule.SchemaDrivenModule

  let parse: Js.Json.t => result<t, exn>
  let parseAny: 'a => result<t, exn>
  let parseJson: string => result<t, exn>
  let parseAsync: Js.Json.t => promise<result<t, exn>>
  let serialize: t => result<Js.Json.t, exn>
  let serializeToUnknown: t => result<unknown, exn>
  let serializeToJson: t => result<string, exn>
}

and api realization for its.

For using add SchemaDrivenRescriptStructPlugin.plugin to engine's plugins array

SchemaDrivenModifyModuleNamePlugin.resi

open SchemaDrivenPlugin

//adds prefix to module name
let prefixPlugin: string => schemaDrivenPlugin

//adds postfix to module name
let postfixPlugin: string => schemaDrivenPlugin

Plugins system and extensibility

types codegeneration produces struct of type resultCodeDeclar:

//SchemaDrivenResultCode.res
type resultCodeDeclar = {
  moduleName: string, //moduleName
  t: string, //type declaration string
  struct: string, //rescript-struct declaration string
  moduleTypes: array<string>, //array of module-types
  funcDeclars: array<string>, //array of extra functions code
}

thats may be converted before printing. plugins is functions type of

//SchemaDrivenPlugin.res
type schemaDrivenPlugin = resultCodeDeclar => resultCodeDeclar

use them for extends your generated types and add advanced api and module-types copability

License

MIT

Author

Anatoly Starodubtsev [email protected]