Rust's Option and Result, implemented for TypeScript.

Overview

oxide.ts

Rust's Option<T> and Result<T, E>, implemented for TypeScript.

Features

Zero dependencies, full test coverage and examples for every function at your fingertips with JSDoc comments.

  • Add more meaning to return types.
  • Express, chain and map values as if you were writing in Rust.
  • Use the match adaptation to simplify conditionals.
  • Quickly test multiple Results or Options with .all and .any.
  • Convert throws and rejections into Results and Options with .safe.

Patch 0.9.10

  • Make guarded functions that return at the first sign of trouble (?).
  • API available both snake_case and camelCase.

Installation

$ npm install oxide.ts --save

Usage

The the best documentation is in the JSDoc and tests directory, there are several examples there not covered in this Readme. If you're using VSCode you should also be able to hover over methods to see some examples.

Core Features

Advanced Features

Tests

npm run test

Option

An Option represents either something, or nothing. If we hold a value of type Option<T>, we know it is either Some<T> or None. Both types share a common API, so we can chain operations without having to worry whether we have Some or None until pulling the value out:

import { Option, Some, None } from "oxide.ts";

function divide(x: number, by: number): Option<number> {
   if (by === 0) {
      return None;
   } else {
      return Some(x / by);
   }
}

const val = divide(100, 20);

// Pull the value out, or throw if None:
const res: number = val.unwrap();
// Throw our own error message in the case of None:
const res: number = val.expect("Division Failed");
// Pull the value out, or use a default if None:
const res: number = val.unwrapOr(1);

// Map the Option<T> to Option<U> by applying a function:
const strval: Option<string> = val.map((num) => `Result = ${num}`);
// Then unwrap the value or use a default if None:
const res: string = strval.unwrapOr("Error");
// Map, assign a default and unwrap in one line:
const res: string = val.mapOr("Error", (num) => `Result = ${num}`);

The type annotations applied to the const variables are for information - the correct types would be inferred.

« To contents

Result

A Result represents either something good (T) or something not so good (E). If we hold a value of type Result<T, E> we know it's either Ok<T> or Err<E>. You could think of a Result as an Option where None has a value.

import { Result, Ok, Err } from "oxide.ts";

function divide(x: number, by: number): Result<number, string> {
   if (by === 0) {
      return Err("Division Failed");
   } else {
      return Ok(x / by);
   }
}

const val = divide(100, 20);

// These are the same as Option (as are many of the other methods):
const res: number = val.unwrap();
const res: number = val.expect("Division Failed");
const res: number = val.unwrapOr(1);
// Map Result<T, E> to Result<U, E>, similar to mapping Option<T> to Option<U>
const strval: Result<string, string> = val.map((num) => `Result = ${num}`);
const res: string = strval.unwrapOr("Error");
const res: string = val.mapOr("Error", (num) => `Result = ${num}`);

// We can unwrap the error, which throws if the Result is Ok:
const err: string = val.unwrapErr();
const err: string = val.expectErr("Expected this to fail");

// Or map the error, mapping Result<T, E> to Result<T, F>
const objerr: Result<number, Error> = val.mapErr((message) => {
   return new Error(message);
});

« To contents

Transformation

Because they are so similar, it's possible to transform an Option<T> into a Result<T, E> and vice versa:

const val: Option<number> = divide(100, 10);

// Here, the argument provides the Err value to be used if val is None:
const res: Result<number, string> = val.okOr("Division Error");

// And to turn it back into an Option:
const opt: Option<number> = res.ok();

Note that converting from Result<T, E> to Option<T> causes the Err value (if any) to be discarded.

« To contents

Nesting

There is no reason you can't nest Option and Result structures. The following is completely valid:

const res: Result<Option<number>, string> = Ok(Some(10));
const val: number = res.unwrap().unwrap();

There are times when this makes sense, consider something like:

import { Result, Option, Some, None, Ok, Err, match } from "oxide.ts";

function search(query: string): Result<Option<SearchResult>, string> {
   const [err, result] = database.search(query);
   if (err) {
      return Err(err);
   } else {
      return result.count > 0 ? Ok(Some(result)) : Ok(None);
   }
}

const result = search("testing");
const output: string = match(result, {
   Ok: match({
      Some: (res) => `Found ${res.count} entries.`,
      None: () => "No results for that search.",
   }),
   Err: (err) => `Error: ${err}`,
});

« To contents

Match

Concisely determine what action should be taken for a given input value. For all the different ways you can use match (including the advanced uses discussed later), the following rules apply:

  • Every branch must have the same return type.
  • As soon as a matching branch is found, no others are checked.

The most basic match can be performed on Option and Result types. This is called mapped matching.

const num: Option<number> = Some(10);
const res = match(num, {
   Some: (n) => n + 1,
   None: () => 0,
});

assert.equal(res, 11);

It's also possible to nest mapped matching and provide defaults. You don't have to include every named branch:

const matchNest = (input: Result<Option<number>, string>) =>
   match(input, {
      Ok: match({
         Some: (n) => `num ${n}`,
      }),
      _: () => "nothing",
   });

assert.equal(matchNest(Ok(Some(10))), "num 10");
assert.equal(matchNest(Ok(None)), "nothing");
assert.equal(matchNest(Err("none")), "nothing");

Note: Using match without the first-position value is not a way to "compile" a match function. Only call match like this within a nested match structure.

« To contents

Safe

Capture the outcome of a function or Promise as an Option<T> or Result<T, E>, preventing throwing (function) or rejection (Promise).

Safe Functions

Calls the passed function with the arguments provided and returns an Option<T> or Result<T, Error>. The outcome is Some/Ok if the function returned, or None/Err if it threw. In the case of Result.safe, any thrown value which is not an Error is converted.

function mightThrow(throws: boolean) {
   if (throws) {
      throw new Error("Throw");
   }
   return "Hello World";
}

const x: Result<string, Error> = Result.safe(mightThrow, true);
assert.equal(x.unwrapErr() instanceof Error, true);
assert.equal(x.unwrapErr().message, "Throw");

const x = Result.safe(() => mightThrow(false));
assert.equal(x.unwrap(), "Hello World");

Note: Any function which returns a Promise (or PromiseLike) value is rejected by the type signature. Result<Promise<T>, Error> or Option<Promise<T>> are not useful types - using it in this way is likely to be a mistake.

Safe Promises

Accepts a Promise and returns a new Promise which always resolves to either an Option<T> or Result<T, Error>. The Result is Some/Ok if the original promise resolved, or None/Err if it rejected. In the case of Result.safe, any rejection value which is not an Error is converted.

async function mightThrow(throws: boolean) {
   if (throws) {
      throw new Error("Throw");
   }
   return "Hello World";
}

const x = await Result.safe(mightThrow(true));
assert.equal(x.unwrapErr() instanceof Error, true);
assert.equal(x.unwrapErr().message, "Throw");

const x = await Result.safe(mightThrow(false));
assert.equal(x.unwrap(), "Hello World");

« To contents

All

Reduce multiple Options or Results to a single one. The first None or Err encountered is returned, otherwise the outcome is a Some/Ok containing an array of all the unwrapped values.

function num(val: number): Result<number, string> {
   return val > 10 ? Ok(val) : Err(`Value ${val} is too low.`);
}

const xyz = Result.all(num(20), num(30), num(40));
const [x, y, z] = xyz.unwrap();
assert.equal(x, 20);
assert.equal(y, 30);
assert.equal(z, 40);

const err = Result.all(num(20), num(5), num(40));
assert.equal(err.isErr(), true);
assert.equal(err.unwrapErr(), "Value 5 is too low.");

« To contents

Any

Reduce multiple Options or Results into a single one. The first Some/Ok found (if any) is returned, otherwise the outcome is None, or in the case of Result - an Err containing an array of all the unwrapped errors.

function num(val: number): Result<number, string> {
   return val > 10 ? Ok(val) : Err(`Value ${val} is too low.`);
}

const x = Result.any(num(5), num(20), num(2));
assert.equal(x.unwrap(), 20);

const efg = Result.any(num(2), num(5), num(8));
const [e, f, g] = efg.unwrapErr();
assert.equal(e, "Value 2 is too low.");
assert.equal(f, "Value 5 is too low.");
assert.equal(g, "Value 8 is too low.");

« To contents

Advanced Features

Word to the wise

The match adaptation shifts the TypeScript idiom and may not be suitable for your project - especially if you work with others.

Combined Matching

It's possible to combine the mapped and chained matching approach.

import { Option, match } from "oxide.ts";

// Easiest to build upon
function player_allowed(player: Option<Player>): boolean {
   return match(player, {
      Some: [
         [{ status: "banned" }, false],
         [{ age: (n) => n > 18 }, true],
      ],
      _: () => false,
   });
}

« To contents

Chained Matching

Can be performed on any type. A chain is an array of branches which are tested in sequence. A branch is a tuple of [<condition>, <result>]. Chain branches follow the following rules:

  • Primitive comparisons test for exact equality (===).
  • Any comparison with the condition _ (Default) succeeds automatically.
  • Matching against arrays is a key-to-key comparison (just like objects). As such, a match condition of [10, 20] doesn't check if 10 and 20 are in the array, but instead checks specifically that index 0 is 10 and index 1 is 20.
  • Tuple elements are "functions first", such that any <condition> that is a function will be called to determine if the branch matches, and any <result> that is a function is called with the input value to determine the return value. To match or return a function, see Fn.
  • On the matter of functions, a <condition> is always a sync function. A <result> can be async, but if so every branch must return an async function.
  • Option and Result types are recursively evaluated to their deepest reachable values and evaluated like any other condition. Using mapped or combined matching for these types is better.

At the end of a chain, an optional default branch may be included which is called with the input value when no other branch matches. If no default is provided, match will throw an error if no other branch matches.

Note: Deeply nesting Option/Result matches may not allow for complete type information to be presented to the user (though they should still be verified). It is also slower (execution time and type computation) than mapped matching or combined matching.

Primitive Example

import { match } from "oxide.ts";

const matchNum = (num: number) =>
   match(num, [
      [5, "five"],
      [(n) => n > 100, "big number"],
      [(n) => n < 0, (n) => `negative ${n}`],
      () => "other",
   ]);

assert.equal(matchNum(5), "five");
assert.equal(matchNum(150), "big number");
assert.equal(matchNum(-20), "negative -20");
assert.equal(matchNum(50), "other");

Object Example

import { match } from "oxide.ts";

const matchObj = (obj: { a: number; b: { c: number } }) =>
   match(obj, [
      [{ a: 5 }, "a is 5"],
      [{ b: { c: 5 } }, "c is 5"],
      [{ a: 10, b: { c: (n) => n > 10 } }, "a 10 c gt10"],
      () => "other",
   ]);

assert.equal(matchObj({ a: 5, b: { c: 5 } }), "a is 5");
assert.equal(matchObj({ a: 50, b: { c: 5 } }), "c is 5");
assert.equal(matchObj({ a: 10, b: { c: 20 } }), "a 10 c gt 10");
assert.equal(matchObj({ a: 8, b: { c: 8 } }), "other");

Array Example

import { match, _ } from "oxide.ts";

const matchArr = (arr: number[]) =>
   match(arr, [
      [[1], "1"],
      [[2, (n) => n > 10], "2 gt10"],
      [[_, 6, _, 12], "_ 6 _ 12"],
      () => "other",
   ]);

assert.equal(matchArr([1, 2, 3]), "1");
assert.equal(matchArr([2, 12, 6]), "2 gt10");
assert.equal(matchArr([3, 6, 9, 12]), "_ 6 _ 12");
assert.equal(matchArr([2, 4, 6]), "other");

« To contents

Comments
  • Expose ResultType under core?

    Expose ResultType under core?

    This is a minor nit, as I can work around this by using import { ResultType } from "oxide.ts/dist/result"

    I use ResultType, because, unfortunately, I have to use instanceof for type inspection, e.g.

          if (result instanceof Result && result.isErr()) {
            const e = result.unwrapErr();
            return handleErrorResponse(e, res);
          }
    

    typescript thinks that Result is {} but instanceof ResultType works.

    If you know another way around this, I'm all ears.

    opened by rrichardson 6
  • Add intoTuple

    Add intoTuple

    Adds the method intoTuple to Result.

    intoTuple returns a tuple [undefined, T], or [Err<E>, undefined] if the result is Err.

    In the Err case, in order to allow for an if (err) comparison, the err member is wrapped in Err.

    There is a question of whether the Err case tuple should contain an unwrapped error instead of Err<E>. One problem that may arise when returning an unwrapped err value is when is when it is a falsy value. In that case, this pattern would be unreliable:

    if (err) {
       // If err is falsy, we will never reach here in the `Err` case.
    } else {
       ...
    }
    

    I can come up with a couple of approaches:

    • In the error case, return [Err<E>, undefined]. The caller can then call err.unwrapErr() within the if (err) clause (As demonstrated in this PR)
    • Return unwrapped values without default, have the caller narrow err !== undefined.
    • Somehow force the caller to provide a truthy default for the err value

    Interested to hear ideas! @traverse1984 Thank you again for your time and feedback.

    opened by sidiousvic 4
  • '.ts' is not a valid suffix for a module -  Consider renaming the repo.

    '.ts' is not a valid suffix for a module - Consider renaming the repo.

    When using oxide.ts in the latest (anything after 4.2) typescript, I get this error:

    index.d.ts:3:53 - error TS2691: An import path cannot end with a '.ts' extension. Consider importing 'oxide.js' instead.
    
    3 import { Option, Some, None, Result, Ok, Err } from "oxide.ts";
                                                           ~~~~~~~~~~                     
    

    IMO it's a bug in tsc, because I'm not trying to import a local file, but a module instead, which should be obvious from the lack of local path separator.

    There are a bunch of people complaining about this, also Deno requires file extensions, instead of banning them. I think this restriction will be lifted, but either way, to avoid current and future errors, would you consider renaming oxide.ts to oxide-ts?

    see: https://github.com/microsoft/TypeScript/issues/38149 https://github.com/microsoft/TypeScript/issues/37582 https://github.com/microsoft/TypeScript/issues/44839

    opened by rrichardson 4
  • Webpack chokes on version 1.0.0

    Webpack chokes on version 1.0.0

    I'm using oxide.ts in a project that I try to test with cypress. Cypress uses webpack. When switching from oxide.ts 0.9.12 to 1.0.0, my application runs fine in the vite dev server, but when testing with cypress I get the following error when I try to import a module from my app in the cypress integration test:

    Error: Webpack Compilation Error
    ./src/store/auth.ts
    Module not found: Error: Can't resolve 'oxide.ts' in '<path>/cypress2/src/store'
    resolve 'oxide.ts' in '<path>/cypress2/src/store'
      Parsed request is a module
      using description file: <path>/cypress2/package.json (relative path: ./src/store)
        Field 'browser' doesn't contain a valid alias configuration
        Looked for and couldn't find the file at the following paths:
    [<path>/cypress2/src/store/node_modules]
    [<path>/cypress2/src/node_modules]
    [<path>/node_modules]
    [/data/node_modules]
    [/node_modules]
    [<path>/cypress2/node_modules/oxide.ts]
    [<path>/cypress2/node_modules/oxide.ts.js]
    [<path>/cypress2/node_modules/oxide.ts.json]
    [<path>/cypress2/node_modules/oxide.ts.jsx]
    [<path>/cypress2/node_modules/oxide.ts.mjs]
    [<path>/cypress2/node_modules/oxide.ts.coffee]
    [<path>/cypress2/node_modules/oxide.ts.ts]
    [<path>/cypress2/node_modules/oxide.ts.tsx]
    [<path>/cypress2/node_modules/oxide.ts/index]
    [<path>/cypress2/node_modules/oxide.ts/index.js]
    [<path>/cypress2/node_modules/oxide.ts/index.json]
    [<path>/cypress2/node_modules/oxide.ts/index.jsx]
    [<path>/cypress2/node_modules/oxide.ts/index.mjs]
    [<path>/cypress2/node_modules/oxide.ts/index.coffee]
    [<path>/cypress2/node_modules/oxide.ts/index.ts]
    [<path>/cypress2/node_modules/oxide.ts/index.tsx]
     @ ./src/store/auth.ts 1:0-38 42:24-28 42:31-35
     @ ./cypress/integration/0-test-cypress/todo.spec.js
     @ multi ./cypress/integration/0-test-cypress/todo.spec.js
    

    Seems like it can't find the entry point for the lib. So I had a quick look at the package.json and the difference seems to be the switch from "main" to "exports". And effectively when I add the "main", even leaving exports in place the issue get's resolved.

    Not sure where the blame lies for this one, whether it's a problem with package.json or with webpack. If you need a MRE, let me know.

    opened by najamelan 4
  • Add intoTuple

    Add intoTuple

    Adds the method intoTuple that was mentioned in #10.

    Convert an existing Option/Result into a tuple containing undefined (or a provided falsey value) and T.

    More than happy to adjust style and details as needed. Great work on this library! Very happy using it.

    opened by sidiousvic 3
  • Add `Result.fromCb` Method

    Add `Result.fromCb` Method

    We have Result.from but what if We want to use callback and use it's exception as Error and return value as Ok also it supports Promise, this method provides it.

    I was using this method in my projects and it was really helpful while working with Promises or Exceptions, I thought that it would be nice if library includes this method.

    Example

    const user: Result<User, UserNotFoundError> = Result.fromCb(() => {
      const foundUser = findUser(); // Throws if cannot find 
      return foundUser
    })
    
    if(user.isErr()) {
      const userError = user.unwrapErr();
    }
    
    user.unwrap();
    
    // Async
    const user: Result<User, UserNotFoundError> = await Result.fromCb(async () => {
      const foundUser = await findUser(); // Throws if cannot find 
      return foundUser
    })
    
    const foo = Result<Foo, FooError> = await Result.fromCb(() => Promise.resolve(5));
    const bar = Result<Bar, BarError> = await Result.fromCb(() => Promise.reject(new Error()));
    
    
    opened by kadiryazici 3
  • refactored Option and Result to use a single class plus statics

    refactored Option and Result to use a single class plus statics

    From the department of "where were you two weeks ago?"

    This changes does away with the distinct ResultType and Result functions, and merges everything into a class with statics.

    I can understand why one might be reluctant to merge this, since the package just hit 1.0

    This refactor is a breaking change, because it gets rid of the Result() and Option() functions. This is fine because, IMO, people should be using Result.from() and Option.from()

    However...

    That is literally the only change to the API.. I had to change 4 lines in the Unit tests to change the functions to use from(). All other tests pass.

    Result(foo) and Option(foo) aren't really possibilities in the Rust stdlib anyways, so I don't know if people expect them in the API.

    IMO it makes the implementation much more straightforward.

    Oh.. I also changed the T symbol variable name to T_ just to keep myself from getting it confused with T the type parameter.

    Also, big shoutout to @n_n from the Typescript Discord server who was a huge help and did much of the initial design.

    opened by rrichardson 3
  • flatten() for Result and Option and nested Ok()'s

    flatten() for Result and Option and nested Ok()'s

    My hope is to copy these methods from Rust: (https://doc.rust-lang.org/src/core/result.rs.html#1704)

    I attempted to implement these, but alas, Typescripts type system is beyond my reckoning. My first approach was a naive one, my expectation was that this would work, though the type error would not be ergonomic if flatten() was called on a non-nested result.

    flatten(this: Result<Result<T, E>, E>): Result<T, E> {
     return this.andThen((x) => x)
    }
    

    When trying to test flatten, I get the unergonomic error message that I expected, but not for the reason I expected. I guess Ok doesn't implicitly convert to Result..

      expect(Ok(Ok(1)).flatten()).to.be.true; 
    

    results in

    The 'this' context of type 'Ok<Err<string>>' is not assignable to method's 'this' of type 'Result<Result<Err<string>, never>, never>'.
      Type 'Err<string>' is not assignable to type 'Result<Err<string>, never>'.
        Type 'string' is not assignable to type 'never'. 
    
    opened by rrichardson 2
  • Unexpected Type Strictness with `unwrap_or`

    Unexpected Type Strictness with `unwrap_or`

    While checking out this library by trying to convert usage of ts-results to this package instead, I ran into an error with unwrap_or. The following code does not compile, though I would expect it should:

    import { type Option } from 'oxide.ts';
    
    type Name = string | undefined;
    
    interface User {
      name: Name;
    }
    
    declare function getName(person: User): Option<string>;
    
    const name: Name = getName({ name: 'Alex' }).unwrapOr(undefined);
    

    Argument of type 'undefined' is not assignable to parameter of type 'string'.

    TypeScript Playground link

    It seems odd to me that unwrap_or would demand it's passed a value that matches the type of the Option that is being unwrapped. I can understand that maybe the types should normally be the same, but not that this library has a strong opinion on the matter.

    If this was the code instead, I would expect an error to occur because undefined doesn't match the types expected by Name, but I would expect that the assignment itself would be the type error, not the usage of unwrap_or

    import { type Option } from 'oxide.ts';
    
    - type Name = string | undefined;
    + type Name = string;
    
    interface User {
      name: Name;
    }
    
    declare function getName(person: User): Option<string>;
    
    const name: Name = getName({ name: 'Alex' }).unwrapOr(undefined);
    

    All that to say: I think that it would make sense that unwrap_or can accept any value, and that the return type of unwrap_or becomes the union of the Option's type and the unwrap_or argument's type. If they're the same, great! If they're not the same, that should be OK too.

    opened by alexlafroscia 1
  • Should intoTuple use undefined instead of null?

    Should intoTuple use undefined instead of null?

    From this comment: https://github.com/traverse1984/oxide.ts/pull/11#issuecomment-1294157267.

    On the one hand, this pattern looks nice and simplifies the case where you want to introduce default values. On the other hand, given that it may sometimes be necessary to be more explicit to correctly narrow the types, it would require somewhat unsightly uses of if (err === undefined) or using ==, neither of which I am a huge fan of.

    opened by traverse1984 4
  • Async API

    Async API

    It would be nice if there were more utilities to work with asynchronous functions, such as an idiomatic way to wrap a Promise with a ResultLike object to allow chaining and unwrapping of async values.

    As an example, neverthrow offers a ResultAsync class which is useful for getting out of Result<Promise<Result<T, E>>, E> hell.

    Consider the following example in oxide.ts:

          const asyncComputation = async (n: number) => (n > 1 ? 0 : n);
    
          const firstComputation: Result<number, null> = Result(1);
    
          const secondComputation: Result<Promise<Result<number, Error>>, null> = firstComputation.map(
              (n) => Result.safe(asyncComputation(n))
          );
    
          const thirdComputation: Result<Promise<Result<string, Error>>, null> = secondComputation.map(
              async (secondComputationPromise) => (await secondComputationPromise).map((n) => n.toString())
          );
    

    With neverthrow's Asynchronous API:

          const asyncComputation = async (n: number) => (n > 1 ? 0 : n);
    
          const firstComputation: Result<number, null> = new Ok(1);
    
          const secondComputation: Result<ResultAsync<number, Error>, null> = firstComputation.map(
              (n) => ResultAsync.fromPromise(asyncComputation(n), () => new Error())
          );
    
          const thirdComputation: Result<string, Error | null> = await secondComputation.asyncAndThen(
              (secondComputationPromise) => secondComputationPromise.map((n) => n.toString())
          );
    

    Perhaps I am missing a way to do it more simply in oxide.ts. If not, would this be a useful adventure to embark on?

    opened by sidiousvic 9
Releases(1.0.0)
Owner
null
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
👨🏼‍🎨 It is a virtual blackboard, where you can make 🖌 drawings through 🖱 the mouse. You have the option to choose 🎨 colors and line thickness.

????‍?? Lets Draw ?? ÍNDICE 1. Lets-Draw 2. Realization of the Project 3. Technologies used 4. Authors 1. Lets-Draw ????‍?? It is a virtual blackboard

Rosamaria Rodriguez 2 Mar 7, 2022
A simple library to draw option menu or other popup inputs and layout on Node.js console.

console-gui-tools A simple library to draw option menu or other popup inputs and layout on Node.js console. console-gui-tools A simple Node.js library

Elia Lazzari 12 Dec 24, 2022
This is a tic-tac-toe game but differs from most others as it carries the option of playing against an AI (COM) or against a friend.

TIC-TAC-TOE This is a simple tic-tac-toe game with the exception of playing against an algorithm or against a friend. At the very start, you have to s

Paul Ibeabuchi C. 4 Jul 2, 2022
BMI Calculator can give us the bmi result of our bmi on the basis of our corresponding height and weight.

BMI means body mass index. Body Mass Index (BMI) is a person's weight in kilograms divided by the square of height in meters.

Bipronath Saha 1 Jan 20, 2022
A great result management solution for schools, hospital, academy and other. If you are a php developer, contribute to this respository for more advancement of the project.

result-management-pro A great result management system for schools, hospital, academy and more. Contributions Willing to add more features to this gre

Adeleye Ayodeji 8 Jun 17, 2022
Based on Google Chrome recorder, implement UI interface capture and notify the result to the target mailbox

chrome-recoder-crawler README-CN Modify the .js file exported by Google Chrome recorder. By default, the innerText property of the node operated in th

wudu 4 Oct 18, 2022
Automatically code review with ktlint result for pull request

GitHub Actions - ktlint-auto-review ?? Automatically reviewed on Pull Request with ktlint Inspired by ScaCap/action-ktlint but without reviewdog. Gett

MinJun Kweon 6 Dec 20, 2022
Text Engraving & Extrusion demo based on Three.js is implemented with Typescript and webpack5. Used THREE-CSGMesh as the core tech to achieve engraving and extrusion results

Text Engraving & Extrusion Text Engraving & Extrusion demo is implemented using Three.js, with Typescript and webpack5. Used THREE-CSGMesh as the core

Jiahong Li 3 Oct 12, 2022
Algorithms and Data Structures implemented in TypeScript for beginners, following best practices.

The Algorithms - TypeScript TypeScript Repository of TheAlgorithms, which implements various algorithms and data structures in TypeScript. These imple

The Algorithms 166 Dec 31, 2022
📝 Algorithms and data structures implemented in JavaScript with explanations and links to further readings

?? Algorithms and data structures implemented in JavaScript with explanations and links to further readings

Oleksii Trekhleb 157.8k Dec 29, 2022
🥞Data Structures and Algorithms explained and implemented in JavaScript + eBook

Data Structures and Algorithms in JavaScript This is the coding implementations of the DSA.js book and the repo for the NPM package. In this repositor

Adrian Mejia 7k Jan 4, 2023
Emem Ekpo 7 Sep 9, 2022
Seamless and lightweight parallax scrolling library implemented in pure JavaScript utilizing Hardware acceleration for extra performance.

parallax-vanilla.js Seamless and lightweight parallax scrolling library implemented in pure JavaScript utilizing Hardware acceleration for extra perfo

Erik Engervall 91 Dec 16, 2022
CLI Progress Bar implemented in NodeJS to track Time, ETA and Steps for any long running jobs in any loops in JS, NodeJS code

NodeJS-ProgressBar CLI Progress Bar for NodeJS and JavaScript to track Time, ETA and Steps for any long running jobs in any loops in JS, NodeJS code D

Atanu Sarkar 5 Nov 14, 2022
Simple Library implemented using HTML, CSS and JavaScript. This is a simple implementation of JavaScript Modules of ES6.

Awesome-books A single page project with the porpuse of storing books' titles and authors. Built With CSS, HTML & Javascript. How to run in your local

Saadat Ali 7 Feb 21, 2022