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

@gekojs/core

v1.3.0

Published

Genetika Kodo: A more genetic style of programming, you could call it genetic coding.

Downloads

645

Readme

GeKo

GeKo proposes a fresh approach to code composition. Imagine connecting pieces of code in a new way, not replacing object-oriented programming (OOP) but building on top of it, inspired by genetics!

Genetika Kodo

GeKo stands for Genetika Kodo, derived from Esperanto words meaning genetic programming or genetic code. So, what makes GeKo "genetic"?

Basics: Genetic Coding Style

In GeKo, we work with two primary classes: Kodo and Gene. You can think of a Kodo as a cell or an abstract structure that possesses behavior. This behavior is constructed by combining different genes:

import {Kodo, Gene} from "geko";

export class Clock extends Gene<{}, { startTime: number; time: number }> {
  startTime: number;
  intervalTimeout: any;

  constructor(public readonly interval: number) {
    super();
  }

  setupSchedule() {
    this.intervalTimeout = setInterval(() => {
      if (!this.isActive || this.isFrozen) return;
      this.write("time", (Date.now() - this.startTime) / 1000);
    }, this.interval * 1000);
  }

  onInit() {
    this.setupSchedule();
  }

  onFreeze() {
    clearInterval(this.intervalTimeout);
  }

  onResume() {
    this.setupSchedule();
  }
}

export class Logger extends Gene<{ message: string | number }> {
  constructor() {
    super();
  }

  async onInit() {
    this.watch("message", (message) => {
      console.log(message);
    });
  }
}

const clockTime = new Wire<number>();

const timer = new Kodo({
  genes: () => [
    new Clock(1).output({ time: [clockTime] }),
    new Logger().input({ message: clockTime }),
  ],
});

timer.init();

In this example, we created a Kodo that logs the time every second. While it might be simpler to write this in plain JavaScript, the gene-based structure allows us to reuse these components in other Kodo instances, facilitating more complex behavior construction.

Wiring

Every gene can receive input and produce output. They are connected via wires, as seen above, enabling the output of one gene to serve as the input for another. You can create a wire type and use it across multiple Kodo instances. Wire creation is straightforward:

const wire = new Wire<WireType>();

Manipulating the Genome

Let’s revisit our timer Kodo. Imagine, like a mad scientist, you want to replace or remove genes on a whim:

// Remove or replace a gene easily
timer.kill();

timer
  .remove({gene: Clock})
  .add(() => [new Clock(0.5).output({ time: [clockTime] })]);

timer.init();

Now, instead of counting each second, the timer will count every half-second. 😄

Gene Lifecycle

Like any living entity, genes in GeKo have a lifecycle. Override these methods to define their behavior:

  • onInit(): Set up the gene to start working.
  • onFreeze(): Temporarily pause the gene's work, allowing it to resume from where it left off.
  • onResume(): Resume the gene's activity after freezing.
  • onKill(): End the gene’s life, freeing all resources. After onKill(), the gene can only operate in a new instance. Note that onFreeze() is always called before onKill().

Kodo Controls

In addition to modifying a Kodo's genome, you can control its lifecycle and create clones:

  • init(): boolean: Starts the Kodo.
  • freeze(): boolean: Pauses activity, relying on each gene's onFreeze() method to ensure complete stoppage.
  • resume(): boolean: Resumes activity from where it was paused.
  • kill(): boolean: Terminates the Kodo, creating fresh instances of all genes upon reinitialization.
  • clone(): Kodo: Creates a new instance of the Kodo, replicating all previous gene additions and removals, including mutations.

Introducing Flow and Shortcuts

With shortcuts you can achieve the same results with a more concise and isolated syntax:

const Timer = (
  input: InputWiring<{
    label: string;
    interval: number;
    duration: number;
  }> = {},
  output: OutputWiring<{ time: number }> = {}
) =>
  $kodo(() => {
    const time = $wire<number>().pipe(output.time);

    return [
      new Clock()
        .input({ interval: input.interval })
        .output({ time: [time] }),
      new Logger().input({
        message: $str(
          input?.label,
          $transform(time, (value) => value.toFixed(1) + "s")
        ).sync(time),
      }),
      new Expiration().input({ time, expiresIn: input.duration }),
    ];
  });

const testFlow = $flow(
  $repeat($num(4), (i) => [
    $if(
      () => i.value < 2,
      Timer({
        label: $str("Solo Timer (i:", i, "):"),
        interval: $num(1),
        duration: $num(5),
      }),
      $else(
        $split(
          $thread(
            Timer({
              label: $str("\nTimer A:"),
              interval: $num(1),
              duration: $num(5),
            }),
            Timer({
              label: $str("Timer B:"),
              interval: $num(1),
              duration: $num(5),
            })
          ),
          $thread(
            Timer({
              label: $str("Timer C:"),
              interval: $num(0.2),
              duration: $num(10),
            })
          )
        )
      )
    ),
  ]),
  $thread(
    Timer({
      label: $str("Timer D:"),
      interval: $num(0.1),
      duration: $num(5),
    })
  )
);

await testFlow.run();

Here, we use a Timer factory to declare inputs and outputs with type parameters, creating an independent timer with its own clock. Thanks to these shortcuts, you can create Kodo factories that interact with the external world safely while maintaining isolation.

This example also introduces Flows for orchestrating multiple Kodo executions.

More to Come

GeKo has a lot of potential! Feel free to share your suggestions. I’m especially excited about exploring emergent behavior and plan to add a library of useful genes so anyone can create unique and elegant solutions. ❤️