All Projects → shqld → tish

shqld / tish

Licence: MIT License
A replacement of shell script with TypeScript, for those who love TypeScript and tired of writing shell script, aiming to emulate shell script in TypeScript.

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to tish

Node Promisepipe
Safely pipe node.js streams while capturing all errors to a single promise
Stars: ✭ 79 (-33.61%)
Mutual labels:  stream, promise
Write
Write data to the file system, creating any intermediate directories if they don't already exist. Used by flat-cache and many others!
Stars: ✭ 68 (-42.86%)
Mutual labels:  stream, promise
Node Fetch
A light-weight module that brings the Fetch API to Node.js
Stars: ✭ 7,176 (+5930.25%)
Mutual labels:  stream, promise
wise-river
Object streaming the way it should be.
Stars: ✭ 33 (-72.27%)
Mutual labels:  stream, promise
Node Instagram
Instagram api client for node that support promises.
Stars: ✭ 185 (+55.46%)
Mutual labels:  stream, promise
Bach
Compose your async functions with elegance.
Stars: ✭ 117 (-1.68%)
Mutual labels:  stream, promise
Download
Download and extract files
Stars: ✭ 1,064 (+794.12%)
Mutual labels:  stream, promise
Scramjet
Simple yet powerful live data computation framework
Stars: ✭ 171 (+43.7%)
Mutual labels:  stream, promise
mst-effect
💫 Designed to be used with MobX-State-Tree to create asynchronous actions using RxJS.
Stars: ✭ 19 (-84.03%)
Mutual labels:  stream, promise
futura
Asynchronous Swift made easy. The project was made by Miquido. https://www.miquido.com/
Stars: ✭ 34 (-71.43%)
Mutual labels:  stream, promise
meros
🪢 A fast utility that makes reading multipart responses simple
Stars: ✭ 109 (-8.4%)
Mutual labels:  stream
android-promise
A Javascript style Promise library for Android JVM
Stars: ✭ 23 (-80.67%)
Mutual labels:  promise
callbag-rs
Rust implementation of the callbag spec for reactive/iterable programming
Stars: ✭ 25 (-78.99%)
Mutual labels:  stream
Promises
It's just another Promise library...
Stars: ✭ 43 (-63.87%)
Mutual labels:  promise
Diffy
🎞️💓🍿 Love streaming - It's always best to watch a movie together ! 🤗
Stars: ✭ 37 (-68.91%)
Mutual labels:  stream
executive
🕴Elegant command execution for Node.
Stars: ✭ 37 (-68.91%)
Mutual labels:  promise
web-streams-polyfill
Web Streams, based on the WHATWG spec reference implementation
Stars: ✭ 198 (+66.39%)
Mutual labels:  stream
stream
Stream. Curating your streams (MIT) License
Stars: ✭ 15 (-87.39%)
Mutual labels:  stream
Streamator
A Spectator Specifically build for Content Creation and Streaming
Stars: ✭ 18 (-84.87%)
Mutual labels:  stream
resloader
🎉A image preloaded plugin and can display the loaded image progress bar
Stars: ✭ 20 (-83.19%)
Mutual labels:  promise

tish

An easy, performant, portable and safe replacement of shell script with TypeScript, aiming to emulate shell in TypeScript instead of calling child_process in fragments.

For those who love TypeScript and are tired of writing shell script.

Examples

import { $ } from 'tish'

try {
    await $('git add .')
} catch (err) {
    console.error(err)
}
import * as stream from 'stream'
import * as util from 'util'
import { dir, stderr } from 'tish'

const pipeline = util.promisify(stream.pipeline)

await dir('~/github.com/shqld/tish', async ($) => {
    console.log(await stdout($('git log --oneline').pipe($('head 5'))))

    try {
        await $('git checkout', { '-b': branch })
    } catch ({ status, command }) {
        console.error(err)
        console.error(await stderr(command))
    }

    await pipeline($("echo console.log('tish')"), fs.createWriteStream('./index.js'))

    await $('git add .')
        .then(() => $('git commit', { '-m': message }))
        .catch(
            (err) =>
                console.error(err) ||
                $('echo Rollbacking...').then(() => $('git reset --hard HEAD'))
        )
})
An advanced example
if (await isFileChanged()) {
    await addAndCommit({
        path: '.',
        message: 'Fix a bug',
        opts: { fixup: 'HEAD~1' },
    })

    console.log(await getCommitLogs(3))
}

async function isFileChanged(): Promise<boolean> {
    const isLocalClean = isSuccessfully($('git diff --exit-code'))
    return !isLocalClean
}

interface Log {
    hash: string
    message: string
}

async function getCommitLogs({ lines = 5 }): Promise<Array<Log>> {
    const rawLogs = await stdout($(`git log --oneline ..HEAD~${lines}`))

    return rawLogs.map((log) => ({
        hash: log.slice(0, 7),
        message: log.slice(8),
    }))
}

async function addAndCommit({
    path,
    message,
    opts,
}: {
    path: string
    message: string
    opts: Partial<{ squash: string; fixup: string }>
}): Command {
    return $('git add', [path]).then(
        $('git commit'),
        args({
            '--message': message,
            '--squash': opts.squash,
            '--fixup': opts.fixup,
        })
    )
}

Why tish

  • Efficient

    Highly optimized with such as Promise, stream, etc. for e.g. piping large stream data.

  • JavaScript-way

    Every command is a pure promise and a What's not. You can await it or catch it, and pipe it for optimized operations.

  • Multi-platform

  • Strongly-typed

Usage

import { $, stdout, stderr, stdouterr, isSuccessful, shell } from 'tish'

// call simply
// -----------
const result = await $('echo hello') // { status = 0, command: Command }

// or
$('echo hello').then((result) => {
    /*...*/
})

// run sequencially
// ----------------
$('git add .')
    .then(() => $('git commit -m "my commit"'))
    .then(() => {
        /*...*/
    })

// run parallel
// ------------
await Promise.allSettled($('git add file_a'), $('git add file_b')).then((results) => {
    /*...*/
})

// read lines async
// ----------------
for await (const log of $('git log --oneline')) {
    console.log(log)
}

// pipe to/from stream
// -------------------
fs.createReadStream('file_a').pipe($('gzip')).pipe(fs.createWriteStream('file_b'))

// pipe to/from command
// --------------------
$('echo hello, world.').pipe($('grep -o world.')).pipe($('xargs echo hello,')) // hello, world.

// get outputs
// -----------
const out = await stdout($('echo hello'))
const err = await stderr($('git non-existent-command'))
const outerr = await stdouterr($('echo hello'))

// error catch
// -----------
try {
    await $('non-existent-command')
} catch ({ status, command }) {
    console.error(status)
    console.error(await stderr(command))
}

// run conditionally
// -----------------
$('git diff --exit-code') // if no diff
    .then(() => console.log('no file changes'))
    .catch(() => $('git commit .'))

// or
if (await isSuccessful($('git diff --exit-code'))) {
    console.log('no file changes')
} else {
    await $('git commit .')
}

// extend shell
// ------------
const { $ } = shell({
    cwd: path.resolve('projects'),
    env: {
        NODE_ENV: 'development',
    },
})

Install

$ npm install -D tish@^0.1.0
$ yarn add -D tish@^0.1.0

What's not

  • NOT a replacement/enhancement of child_process.*

Motivation

Writing shell script is simply hard. Sometimes we’d like to write some operations in JavaScript(TypeScript).

However it's also tough to write a script in JavaScript with child_process of Node.js and since since a single Node.js process takes ~30ms at least for the startup and consumes a lot of memory, it's not suitable for iterations such as inside of xargs or something.

Also, when it comes to write everything in JavaScript then, still there would be a problem: performance. Even using great libraries that wraps child_process such as https://github.com/sindresorhus/execa, still it’s hard to write a performant script for multiple related operations.

We need a library that entirely replace shell script with JavaScript keeping performance.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].