SkillAgentSearch skills...

MojiScript

MojiScript is an async-first, opinionated, and functional library

Install / Use

/learn @joelnet/MojiScript
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

MojiScript project:experimental build status Coverage Status project:experimental All Contributors

MojiScript logo

MojiScript is an Async First, opinionated, and functional library and language designed to have 100% compatibility with JavaScript engines. This will allow full access to JavaScript modules (NPM) and all tooling already available to JavaScript. This means that MojiScript language features can run in any JavaScript application and vice-versa.

MojiScript's design is derived from Functional Programming concepts such as Currying, Partial Application, Function Composition, Category Theory, and Atomic Design.

NEW: Join the discussion in the MojiScript Discord chat!

View the Documentation

Environment Support

This library supports ES6. If you need to support ES5, you will need to transpile it with Babel.

Table of Contents

Philosophy

The MojiScript philosophy is to provide a functional-style application framework, making asynchronous tasks intuitive and easy.

MojiScript is heavily opinionated and prevents code considered to be async-unfriendly like for loops and statement blocks.

Benefits

  • The Asynchronous-first design greatly simplifies writing and reasoning about Asynchronous code. Worry less about callbacks, promises, async, await, etc.
  • Atomic Design, function composition, and Pipes encourages maximum code re-use, testability and the ability to compose smaller functions into larger ones.
  • Compatibility with ECMAScript gives our applications full access to the JavaScript ecosystem. It also allows us to import elements from MojiScript into existing JavaScript applications.
  • A modular design allows for features to be imported on an as needed basis, keeping packages small.
  • Plays well with functional libraries. Check out the Complementary Libraries section for libraries that can benefit your MojiScript applications.

Quickstart

Clone the starter app.

git clone https://github.com/joelnet/mojiscript-starter-app.git
cd mojiscript-starter-app

Install, build, and run

npm ci
npm run build
npm start

If everything works, you should see:

Hello World

If your editor does not format on save, you can run the following command:

npm run watch

Style Guide

All values must be declared with const.

// BAD
let value = {}

// GOOD
const value = {}

Variables should be named in lower camel case.

// BAD
const AddNumbers = x => y => x + y

// GOOD
const addNumbers = x => y => x + y

Expressions or Pipes and their arguments should be separated with a space. Arguments should be surrounded with parentheses. Further discussed at #438.

// BAD
add(1)(2)

// GOOD
add (1) (2)

Prefer String Templates

// BAD
const func = x => `Value: ${x}`

// GOOD
const func = $`Value: ${0}`

// BAD
const func = ({ prop }) => `Prop: ${prop}`

// GOOD
const func = $`Prop: ${'prop'}`

Following Atomic Design principles, code should be broken down into Atoms. This maximizes reusability, testability, composability, and readability.

// BAD
const getOrdersText = ifElse (({ length }) => length > 0) ($`${0} orders`) ($`No Orders`)

// GOOD
const hasOrders = ({ length }) => length > 0
const getOrdersText = ifElse (hasOrders) ($`${0} orders`) ($`No Orders`)

// GOOD
const hasOrders = ({ length }) => length > 0
const ifHasOrders = ifElse (hasOrders)
const getOrdersText = ifHasOrders ($`${0} orders`) ($`No Orders`)

ifElse and the condition should be on the same line. Longer statements can be broken out into multiple lines. If it is long, consider breaking it down further.

// BAD
ifElse
  (lessThan0)
  (Math.abs)
  (Math.sqrt)

// GOOD
ifElse (lessThan0) (Math.abs) (Math.sqrt)

// GOOD
ifElse (lessThan0)
  (Math.abs)
  (Math.sqrt)

Pipes must be multi-line.

// BAD
const main = pipe ([ add ])

// GOOD
const main = pipe ([
  add
])

Arrays must have a space after the opening bracket and before the closing bracket.

// BAD
const array = [1, 2, 3]

// GOOD
const array = [ 1, 2, 3 ]

No semi-colons.

// BAD
const value = 888;

// GOOD
const value = 888

Complementary Libraries

  • Sanctuary - Recommended collection of useful functions.
  • Ramda - Another recommended collection of useful functions.
  • List - 🐆 An immutable list with unmatched performance and a comprehensive functional API. (use list/curried)

Variables

Variables are constant.

// constant
const path = './data'

path = './hello'
//=> Error("Path is read-only")

Objects declared with const are now also immutable!

const state = {
  // mutable
  count: 0
}

state.count = 1
//=> error  Unallowed reassignment  fp/no-mutation

A variable can be a value (Number, String, Object), an Expression, or a Pipe.

Objects

Objects are plain data objects.

const cat = {
  name: 'mojo',
  dob: Date.parse('July 14, 2009'),
  weight: 14
}

note: Objects may contain functions, but those functions will not have a reference to the object itself. Behavior and data should be decoupled.

String Templates

String Templates make strings a joy to work with.

import $ from 'mojiscript/string/template'

const searchTemplate = $`Searching for: "${0}"`
const nameTemplate = $`${'first'} ${'last'}`

searchTemplate ('Skywalker') //=> 'Searching for: "Skywalker"'
nameTemplate ({ first: 'Luke', last: 'Skywalker' }) //=> 'Luke Skywalker'

Have a look at the Axios Example for more on how String Templates can improve your code.

Expressions

Expressions can be compared to a synchronous function that takes 1 argument and returns 1 argument.

const increase = x => x + 1

Multiple Arguments

Multiple arguments can be simulated a couple different ways.

Currying and Closures

const add = x => y => x + y
add (3) (4) //=> 7

Objects

const add = ({ x, y }) => x + y
add ({ x: 3, y: 4 }) //=> 7

Arrays

const add = ([x, y]) => x + y
add ([3, 4]) //=> 7

Compound Expressions

Compound expressions combine multiple expressions. The last expression will return the value of the Compound Expression. This is typically done to handle side effects.

const tap = func => value => (
  func(value),
  value
)

Pipes

Pipes can be compared to an asynchronous function that takes 1 argument and returns 1 argument.

Each pipe can contain multiple Pipes or Expressions. A Pipe will return the result of the final Pipe or Expression.

// increase :: Number -> Number
const increase = pipe ([
  x => x + 1
])

increase (1) //=> 2

Pipes are a stream of data

A Pipe should be viewed as a stream of data, that performs Morphisms (or transformation between Categories) along each step.

import pipe from 'mojiscript/core/pipe'
import run from 'mojiscript/core/run'
import log from 'mojiscript/console/log'

const state = 4

const main = pipe ([
  //         |
  //         | 4
  //         ▼
  /*-------------------*/
  /**/  x => x + 5,  /**/
  /*-------------------*/
  //         |
  //         | 9
  //         ▼
  /*-------------------*/
  /**/  x => x * 2,  /**/
  /*-------------------*/
  //         |
  //         | 18
  //         ▼
  /*-------------------*/
  /**/      log,     /**/
  /*-------------------*/
  //         |
  //         | 18
  //         ▼
])

run ({ 
View on GitHub
GitHub Stars147
CategoryDevelopment
Updated5mo ago
Forks12

Languages

JavaScript

Security Score

92/100

Audited on Oct 10, 2025

No findings