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

railway-js

v0.0.4

Published

A small repo that helps write railway-oriented JS

Downloads

6

Readme

Railway - railway-oriented JS

Railway-oriented programming is a powerful tool in handling both happy and unhappy paths. It's usually based on Some "Result" Algebraic type and pattern matching (both are missing in JS) and streamlines logic into one "happy" path and one "unhappy" path while keeping functions small and composable.

Of course, in JS the closest to the "Result" type you have built-in is the Promise. You can do Railway oriented programming very well with promises. However, I end up having some IO functions that return Promises and some other pure ones that transform data or do something meaningful. So I want this library to help me do both, but in a way that I can compose functions and handle errors in a way as if I all parts of the "pipe" return promises

Example:

const todos = []

const DEFAULT_MESSAGE = 'Failed assertion'

const assert = (validator, message = DEFAULT_MESSAGE) => (data) => {
  if (!validator(data)) {
    throw new Error(message)
  }
  return data
}

const taskIsString = assert(
  ({ task }) => typeof task === 'string',
  'task should be a string'
)
const isNotTooLong = assert(
  ({ task }) => task.length > 0 && task.length <= 120,
  'task should be between 1 and 120 characters'
)
const isValidTask = todo => taskIsString(todo) && isNotTooLong(todo)

// sync functions
const validateTodo = todo => isValidTask(todo)
const traceSaved = (saved) => { console.log('Saved todo', saved); return saved }
const respondSuccess = saved => ({ success: true, saved })
const respondFailure = error => ({ success: false, error: error.message })

// async functions
const saveTodo = async (todo) => {
  const id = todos.push(todo)
  return { ...todo, id }
}

// handles Request that creates a todo for a user
const createTodo = railway(
  validateTodo, // falls through
  saveTodo, // falls through
  traceSaved, // falls through
  [respondSuccess, respondFailure],
)

const createTodoThrowing = railway(
  validateTodo, // falls through
  saveTodo, // falls through
  traceSaved // falls through
)

createTodo({ task: 'First task' })
  .then(console.log) // => { success: true, saved: { task: 'First task', id: 1 } }

// because these are handled by the respondFailure and respondSuccess functions
// the function result will always return something and therefore execute the 'then' handler
// (in this case though the 'error.message' part can throw if error is undefined)
createTodo({ task: 123 })
  .then(console.log) // => { success: false, error: 'task should be a string' }

// This will behave as a simple pipe function that combines both sync and async functions
// and therefore execute the catch handler
createTodoThrowing({ task: 123 })
  .catch(err => console.log(`failed "${err.message}"`)) // => failed "task should be a string"


// this means that, when used for handling requests (e.g. express.js) functions can be written this way

app.post(
  '/todo',
  (req, res) => createTodo(req.body).then(res.json)
)