/gen-js-block

a js library to generate js-code using js code

Primary LanguageTypeScriptMIT LicenseMIT

gen-js-block

npm npm

GitHub issues GitHub forks GitHub stars GitHub license

a js-library to generate js code with js code

if you like this package please star it in github

Usage

all variables that start with $ are called template variables

if you use a template variable in an if statement it becomes a template if-statement

and the code inside will not be in the output if the condition is false

import { Block } from "gen-js-block";

const block = new Block(($condition) => {
  if ($condition) {
    console.log("$condition is true");
  } else {
    console.log("$condition is false");
  }
});

console.log(block.build({ $condition: true })); // => {console.log("$condition is true");}
console.log(block.build({ $condition: false })); // => {console.log("$condition is false");}

similarly for-of and for-in loops with template variables in them are called template loops (c-style loops can't be template maybe in the future)

import { Block } from "gen-js-block";

const block = new Block(($array) => {
  for (const $item of $array) {
    console.log($item);
  }
});

console.log(block.build({ $array: [0, 1, 2] }));
// => {const $item = 0;console.log($item);};{const $item = 1;console.log($item);};{const $item = 2;console.log($item)};

and also the value of template variables will be included in the code, so you can use them in the result code

import { Block } from "gen-js-block";

const block = new Block(($message) => {
  console.log($message);
});

console.log(block.build({ $message: "hello world!" }));
// => {const $message = "hello world!";console.log($message);}

also if you call a function that starts with $ and it's an argument of the function passed to the block class then the string returned from that call will be added to the result code as is

example: let's say you want to make code that returns a function that returns a random number

import { Block } from "gen-js-block";

const block = new Block(($fn) => {
  function result() {
    return $fn();
  }
  result;
});

const code = block.build({ $fn: Math.random });
// => {const $fn = undefined;function result() { return 0.5542537758332537 }; result;}
console.log(eval(code)());
// => 0.5542537758332537
console.log(eval(code)());
// => 0.5542537758332537

example 2: let's say you want to print numbers from 3 to 0 but using recursion instead of loops...

function recur(n: number) {
  const block = new Block(($fn: any, $n: any) => {
    if ($n < 1) {
      console.log(0);
    } else {
      console.log($n);
      // these brackets are needed in these case
      // and most cases
      {
        $fn($n - 1);
      }
    }
  });

  return block.build({ $n: n, $fn: recur });
}
const code = recur(3);
console.log(code);
// => const $fn = undefined;const $n = 3;{console.log($n);{const $fn = undefined;const $n = 2;{console.log($n);{const $fn = undefined;const $n = 1;{console.log($n);{const $fn = undefined;const $n = 0;{console.log(0);};}};}};}}
eval(code);
// => 3
// => 2
// => 1
// => 0

inline options

you might have noticed that instead of replacing template variables in the result code gen-js-block defines them on top, if you want it to replace it instead use this

import { Block } from "gen-js-block";

const block = new Block(
  ($message) => {
    console.log($message);
  },
  { inlineVariables: true }
);

console.log(block.build({ $message: "hello world!" }));
// => console.log("hello world");

if you want to inline specific variables to this

import { Block } from "gen-js-block";

const block = new Block(
  ($message, $message2) => {
    console.log($message, $message2);
  },
  { inlineVariables: ["$message"] }
);

console.log(
  block.build({ $message: "hello world!", $message2: "hello, again" })
);
// => const $message2 = "hello again";console.log("hello world", $message2);

replace option

this will not consider if statements and for-loops that contain specified template vars as template if-statements and for loops instead it will replace it with given code

import { Block, insertCode } from "gen-js-block";

const block = new Block(($some) => {
  if ($some === "one") $some = 1;
  else if ($some === "two") $some = 2;
  else $some = null;
}, { replace: ["$some"] });

// you must use insertCode function
console.log(block.build({ $some: insertCode("hello.world") }));
// ==> if (hello.world === "one") { hello.world = 1 } else if (hello.world === 2) { hello.world = 1 } else { hello.world = null; }

eval method

if you want to build the code then run it you can use the eval method

import { Block } from "gen-js-block";

const block = new Block(($message) => {
  console.log($message);
});

block.eval({ $message: "hello world!" });
// prints "hello world!"

usage in typescript

all template variables must be typed like so

import { Block } from "gen-js-block";

const block = new Block<{ $message: string; $array: number[] }>(
  ($message: string, $array: number[]) => {
    console.log($message, $array);
  }
);

and if there is a non-template variables that will be defined else where you pass it as an argument

const block = new Block<{}>((definedElseWhere: string) => {
  // no errors!
  console.log(definedElseWhere);
});

important notes

  1. all template variables must be start with $

  2. new variables defined in template loop must start with $ (since they're template vars). example:

    // will throw an error
    const block = new Block(($array) => {
      // should be $item...
      for (const item of $array) {
        console.log(item);
      }
    });
    
    block.build({ $array: [0, 1, 2] });
  3. result code inside template loops or ifs will be warped in a block. example:

    // this wont error
    const block = new Block(($condition) => {
      const some = 0;
      if ($condition) {
        const some = 1;
        console.log(some);
      }
      console.log(some);
    });
    
    block.build({ $condition: true });
    // => {const some = 0;{const some = 1;console.log(some);}console.log(some);}
  4. c-style loops can't be template loops (at least for now), example:

    // won't work (will be in result code)
    const block = new Block(($array) => {
      for (let $i = 0; $i < $array.length; $i++) {
        console.log($array[$i]);
      }
    });
    
    block.build({ $array: [0, 1, 2] });
    // => {for (let $i = 0; $i < $array.length; $i++) {console.log($array[$i]);}}
    // not the output you want!
  5. no template switch statements (at least for now)

    // won't work!
    const block = new Block(($number) => {
      switch ($number) {
        case 0:
          console.log("zero");
        case 1:
          console.log("one");
      }
    });
  6. can't non-identifier parameters to the function passed to block (since it doesn't make sense)

    // all of these will error
    
    const block = new Block((...$args) => /* ... */);
    
    const block = new Block(([$item1, $item2]) => /* ... */);
    
    const block = new Block(({ $key }) => /* ... */);