• Stars
    star
    308
  • Rank 135,712 (Top 3 %)
  • Language
    JavaScript
  • Created almost 9 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Traverse objects and arrays with ease

End-of-life

July 2020: Thank you to all the users and contributors who have made this project possible. Moving forward, please consider alternatives such as immer.


scour.js

Traverse objects and arrays immutably

Scour is a general-purpose library for dealing with JSON trees.
As a simple utility with a broad purpose, it can be used to solve many problems. Use it to:

  • Manage your Redux datastore.
  • Provide a model layer to access data in your single-page app. →
  • Navigate a large JSON tree easily.
  • Rejoice in having a lightweight alternative to Immutable.js. (Compare)

Status

Install

npm install --save-exact scourjs
window.scour                       // non commonjs
const scour = require('scourjs')   // commonjs/node
import scour from 'scourjs'        // es6 modules

Features

Calling scour(object) returns a wrapper that you can use to traverse object. Use get() to retrieve values.

data =
  { users:
    { 1: { name: 'john' },
      2: { name: 'shane', confirmed: true },
      3: { name: 'barry', confirmed: true } } }
scour(data).get('users', '1', 'name')   // => 'john'

Traversal

Use go() to dig into the structure. It will return another scour wrapper scoped to that object.

data =
  { users:
    { admins:
      { bob: { logged_in: true },
        sue: { logged_in: false } } } }
users  = scour(data).go('users')            // => [scour (admins)]
admins = scour(data).go('users', 'admins')  // => [scour (bob, sue)]

admins.go('bob').get('logged_in')           // => true

Chaining

scour() provides a wrapper that can be used to chain methods. This is inspired by Underscore and Lodash.

scour(data)
  .go('users')
  .filter({ admin: true })
  .value

Immutable modifications

Use set() to update values. Scout treats all data as immutable, so this doesn't modify your original data, but gets you a new one with the modifications made.

data = scour(data)
  .set(['users', '1', 'updated_at'], +new Date())
  .value

// => { users:
//      { 1: { name: 'john', updated_at: 1450667171188 },
//        2: { name: 'shane', confirmed: true },
//        3: { name: 'barry', confirmed: true } } }

Advanced traversing

Use filter() to filter results with advanced querying.

users = scour(data).go('users')

users
  .filter({ confirmed: true })
  .at(0)
  .get('name')   // => 'shane'

Models

Use use() to add your own methods to certain keypaths. This makes them behave like models.
See a detailed example to learn more.

Sample data
data =
  { artists:
    { 1: { first_name: 'Louie', last_name: 'Armstrong' },
      2: { first_name: 'Miles', last_name: 'Davis' } } }
Your models
Root = {
  artists () { return this.go('artists') }
}

Artist = {
  fullname () {
    return this.get('first_name') + ' ' + this.get('last_name')
  }
}
Using with scour
db = scour(data)
  .use({
    '': Root,
    'artists.*': Artist
  })

db.artists().find({ name: 'Miles' }).fullname()
//=> 'Miles Davis'

API

scour

scour(object)

Returns a scour instance wrapping object.

scour(obj)

It can be called on any Object or Array. (In fact, it can be called on anything, but is only generally useful for Objects and Arrays.)

data = { menu: { visible: true, position: 'left' } }
scour(data).get('menu.visible')

list = [ { id: 2 }, { id: 5 }, { id: 12 } ]
scour(list).get('0.id')

Chaining: You can use it to start method chains. In fact, the intended use is to keep your root scour object around, and chain from this.

db = scour({ menu: { visible: true, position: 'left' } })

// Elsewhere:
menu = db.go('menu')
menu.get('visible')

Properties: It the root, value and keypath properties.

s = scour(obj)
s.root             // => [scour object]
s.value            // => raw data (that is, `obj`)
s.keypath          // => string array

Accessing the value: You can access the raw data using value.

db = scour(data)
db.value               // => same as `data`
db.go('users').value   // => same as `data.users`

Chaining methods

These methods are used to traverse nested structures. All these methods return scour instances, making them suitable for chaining.

On null values

Note that undefined, false and null values are still scour-wrapped when returned from go(), at() and [find()].

list = [ { name: 'Homer' }, { name: 'Bart' } ]

scour(list).at(4)         // => [ scour undefined ]
scour(list).at(4).value   // => undefined

This is done so that you can chain methods safely even when something is null. This behavior is consistent with what you'd expect with jQuery.

data = { users: { ... } }
db = scour(data)

db.go('blogposts').map((post) => post.get('title'))
// => []

go

go(keypath...)

Navigates down to a given keypath. Always returns a scour instance. Rules on null values apply.

data =
  { users:
    { 12: { name: 'steve', last: 'jobs' },
      23: { name: 'bill', last: 'gates' } } }

scour(data).go('users')                    // => [scour (users)]
scour(data).go('users', '12')              // => [scour (name, last)]
scour(data).go('users', '12').get('name')  // => 'steve'

Dot notation: Keypaths can be given in dot notation or as an array. These statements are equivalent.

scour(data).go('users.12')
scour(data).go('users', '12')
scour(data).go(['users', '12'])

Non-objects: If you use it on a non-object or non-array value, it will still be returned as a scour instance. This is not likely what you want; use get() instead.

attr = scour(data).go('users', '12', 'name')
attr           // => [scour object]
attr.value     // => 'steve'
attr.keypath   // => ['users', '12', 'name']

at

at(index)

Returns the item at index. This differs from go as this searches by index, not by key. This returns a the raw value, unlike getAt(). Rules on null values apply.

users =
  { 12: { name: 'steve' },
    23: { name: 'bill' } }

scour(users).at(0)          // => [scour { name: 'steve' }]
scour(users).get(12)        // => [scour { name: 'steve' }]

getAt

getAt(index)

Returns the item at index. This differs from get as this searches by index, not by key. This returns a the raw value, unlike at(). (Since v0.5)

users =
  { 12: { name: 'steve' },
    23: { name: 'bill' } }

scour(users).at(0)           // => [scour { name: 'steve' }]
scour(users).getAt(0)        // => { name: 'steve' }

filter

filter(conditions)

Sifts through the values and returns a set that matches given conditions. Supports simple objects, MongoDB-style queries, and functions.

scour(data).filter({ name: 'Moe' })
scour(data).filter({ name: { $in: ['Larry', 'Curly'] })
scour(data).filter((item) => item.get('name') === 'Moe')

Filter by object: If you pass an object as a condition, filter() will check if that object coincides with the objects in the collection.

scour(data).filter({ name: 'Moe' })

Filter by function: You may pass a function as a parameter. In this case, the item being passed to the callback will be a scour-wrapped object. The result will also be a scour-wrapped object, making it chainable.

scour(data)
  .filter((item, key) => +item.get('price') > 200)
  .sortBy('price')
  .first()

Advanced queries: MongoDB-style queries are supported as provided by sift.js. For reference, see MongoDB Query Operators.

scour(products).filter({ price: { $gt: 200 })
scour(articles).filter({ published_at: { $not: null }})

Arrays or objects: Both arrays and array-like objects are supported. In this example below, an object will be used as the input.

devices =
  { 1: { id: 1, name: 'Phone', mobile: true },
    2: { id: 2, name: 'Tablet', mobile: true },
    3: { id: 3, name: 'Desktop', mobile: false } }

scour(devices).filter({ mobile: true }).len()
// => 2

Also see scour.filter() for the unwrapped version.

reject

reject(conditions)

Inverse of filter() -- see filter() documentation for details.

find

find(conditions)

Returns the first value that matches conditions. Supports MongoDB-style queries. For reference, see MongoDB Query Operators. Also see filter(), as this is functionally-equivalent to the first result of filter(). Rules on null values apply.

scour(data).find({ name: 'john' })
scour(data).find({ name: { $in: ['moe', 'larry'] })

first

first()

Returns the first result as a scour-wrapped object. This is equivalent to at(0).

last

last()

Returns the first result as a scour-wrapped object. This is equivalent to at(len() - 1): see at() and len().

sortBy

sortBy(condition)

Sorts a collection. Returns a scour-wrapped object suitable for chaining. Like other chainable methods, this works on arrays as well as objects. (Since v0.8)

data =
  { 0: { name: 'Wilma' },
    1: { name: 'Barney' },
    2: { name: 'Fred' } }

scour(data).sortBy('name').value
// { 1: { name: 'Barney' },
//   2: { name: 'Fred' },
//   0: { name: 'Wilma' } }

Conditions: The given condition can be a string or a function. When it's given as a function, the item being passed is a scour-wrapped object, just like in forEach() (et al). These two examples below are functionally-equivalent.

scour(data).sortBy('name')
scour(data).sortBy((item) => item.get('name'))

You may also define nested keys in dot-notation:

scour(data).sortBy('user.name')

Reading methods

For retrieving data.

get

get(keypath...)

Returns data in a given keypath.

data =
  { users:
    { 12: { name: 'steve' },
      23: { name: 'bill' } } }

scour(data).get('users')       // => same as data.users
scour(data).go('users').value  // => same as data.users

Dot notation: Like go(), the keypath can be given in dot notation.

scour(data).get('books.featured.name')
scour(data).get('books', 'featured', 'name')

len

len()

Returns the length of the object or array. For objects, it returns the number of keys.

users =
  { 12: { name: 'steve' },
    23: { name: 'bill' } }

names = scour(users).len()  // => 2

toArray

toArray()

Returns an array. If the the value is an object, it returns the values of that object. If the value is an array, it returns it as is. Also aliased as values().

users =
  { 12: { name: 'steve' },
    23: { name: 'bill' } }

names = scour(users).toArray()
// => [ {name: 'steve'}, {name: 'bill'} ]

keys

keys()

Returns keys. If the value is an array, this returns the array's indices. Also see toArray() to retrieve the values instead.

Writing methods

These are methods for modifying an object/array tree immutably. Note that all these functions are immutable--it will not modify existing data, but rather spawn new objects with the modifications done on them.

set

set(keypath, value)

Sets values immutably. Returns a copy of the same object (scour-wrapped) with the modifications applied.

data = { bob: { name: 'Bob' } }
db = scour(data)
db = db.set([ 'bob', 'name' ], 'Robert')
// db.value == { bob: { name: 'Robert' } }

Immutability: This is an immutable function, and will return a new object. It won't modify your original object.

profile = scour({ name: 'John' })
profile2 = profile.set('email', '[email protected]')

profile.value   // => { name: 'John' }
profile2.value  // => { name: 'John', email: '[email protected]' }

Using within a scope: Be aware that using all writing methods (set(), del(), extend()) on scoped objects (ie, made with go()) will spawn a new root object. If you're keeping a reference to the root object, you'll need to update it accordingly.

db = scour(data)
book = db.go('book')
book.root === db       // correct so far

book = book.set('title', 'IQ84')
book = book.del('sale_price')
book.root !== db      // `root` has been updated

Dot notation: Like go() and get(), the keypath can be given in dot notation or an array.

scour(data).set('menu.left.visible', true)
scour(data).set(['menu', 'left', 'visible'], true)

del

del(keypath)

Deletes values immutably. Returns a copy of the same object (scour-wrapped) with the modifications applied.

Like set(), the keypath can be given in dot notation or an array.

scour(data).del('menu.left.visible')
scour(data).del(['menu', 'left', 'visible'])

See set() for more information on working with immutables.

extend

extend(objects...)

Extends the data with more values. Returns a scour-wrapped object. Just like Object.assign, you may pass multiple objects to the parameters.

data  = { a: 1, b: 2 }
data2 = scour(data).extend({ c: 3 })
data2  // => [scour { a: 1, b: 2, c: 3 }]
data2.value   // => { a: 1, b: 2, c: 3 }

When used with anything non-object, it will be overridden.

data = {}
db = scour(data)
db = db.go('state').extend({ pressed: true }).root

db.value  // => { state: { pressed: true } }

See set() for more information on working with immutables.

Utility methods

For stuff.

use

use(extensions)

Extends functionality for certain keypaths with custom methods. See Extensions example for examples.

data =
  { users:
    { 12: { name: 'steve', surname: 'jobs' },
      23: { name: 'bill', surname: 'gates' } } }

extensions = {
  'users.*': {
    fullname () {
      return this.get('name') + ' ' + this.get('surname')
    }
  }
}

scour(data)
  .use(extensions)
  .get('users', 12)
  .fullname()       // => 'bill gates'

Extensions format: The parameter extension is an object, with keys being keypath globs, and values being properties to be extended.

.use({
  'books.*': { ... },
  'authors.*': { ... },
  'publishers.*': { ... }
 })

Extending root: To bind properties to the root method, use an empty string as the keypath.

.use({
  '': {
    users() { return this.go('users') },
    authors() { return this.go('authors') }
  }
})

Keypath filtering: You can use glob-like * and ** to match parts of a keypath. A * will match any one segment, and ** will match one or many segments. Here are some examples:

  • users.* - will match users.1, but not users.1.photos
  • users.** - will match users.1.photos
  • users.*.photos - will match users.1.photos
  • ** will match anything

When using outside root: Any extensions in a scoped object (ie, made with go()) will be used relative to it. For instance, if you define an extension to admins.* inside .go('users'), it will affect `users.

data = { users: { john: { } }
db = scour(data)

users = db.go('users')
  .use({ '*': { hasName () { return !!this.get('name') } })

users.go('john').hasName()      // works

While this is supported, it is not recommended: these extensions will not propagate back to the root, and any objects taken from the root will not have those extensions applied to them.

users.go('john').hasName()              // works
db.go('users.john').hasName()           // doesn't work

index

index(keypath, field)

Sets up indices to improve filter() performance. (Since v0.12)

  • keypath (String | Array) - the keypath of the collection.
  • field (String) - the name of the field to be indexed.
data =
  { users:
    { 1: { name: 'John Creamer' },
      2: { name: 'Stephane K' } } }

db = scour(data).index('users', 'name')
db.filter({ name: 'Stephane K' })

Doing this will add an index in the root (acccessible via scour().indices) to make searches faster for certain filter() queries. Any writing actions (set(), extend(), del()) will automatically update the index.

See scour-search for more information on indexing.

toJSON

toJSON()

Returns the value for serialization. This allows JSON.stringify() to work with scour-wrapped objects. The name of this method is a bit confusing, as it doesn't actually return a JSON string — but I'm afraid that it's the way that the JavaScript API for JSON.stringify works.

equal

equal(other)

Checks for equality between two Scour-wrapped objects.

a = scour(data)
b = scour(data)

a.equal(b)   // => true

Iteration methods

These methods are generally useful for collections. These methods can work with either arrays or array-like objects, such as below.

subjects =
  { 1: { id: 1, title: 'Math', level: 101 },
    2: { id: 2, title: 'Science', level: 103 },
    3: { id: 3, title: 'History', level: 102 } }

Values: For all these functions, The items passed onto the callbacks is a scour-wrapped object. Use item.value or this to access the raw values.

scour(subjects).forEach((subject, key) => {
  console.log(subject.get('title'))
})

Return values: For methods that return values (such as map(), the returned results is not a scour-wrapped object, and isn't suitable for chaining.

scour(subjects).map((subject, key) => {
  return subject.get('title') + ' ' + subject.get('level')
})
// => [ 'Math 101', 'Science 103', 'History 102' ]

forEach

forEach(function(item, key, index))

Loops through each item. Supports both arrays and objects. The rules specified in Iteration methods apply.

users =
  { 12: { name: 'steve' },
    23: { name: 'bill' } }

scour(users).each((user, key) => {
  console.log(user.get('name'))
})

The values passed onto the function are:

  • item - the value; always a scour object.
  • key - the key.
  • index - the index.

each

each(fn)

Alias for forEach.

map

map(function(item, key))

Loops through each item and returns an array based on the iterator's return values. Supports both arrays and objects. The rules specified in Iteration methods apply.

users =
  { 12: { name: 'Steve' },
    23: { name: 'Bill' } }

names = scour(users).map((user, key) => user.get('name'))
// => [ 'Steve', 'Bill' ]

mapObject

mapObject(function(val, key))

Creates a new Object with with the results of calling a provided function on every element in this array. Works like Array#map, but also works on objects as well as arrays, and it returns an object instead. The rules specified in Iteration methods apply.

See scour.mapObject() for details and the non-wrapped version.

indexedMap

indexedMap(function(val, key))

Creates a new Object with with the results of calling a provided function returning the keys and values for the new object. The rules specified in Iteration methods apply.

See scour.indexedMap() for details and the non-wrapped version.

reset

reset(value, options)

Returns a clone with the value replaced. The new instance will retain the same properties, so things like use() extensions are carried over.

db = scour({ name: 'hello' })
db.value  //=> { name: 'hello' }

db = db.reset({})
db.value  // => {}

This is useful for, say, using Scour with Redux and implementing an action to reset the state back to empty.

Attributes

These attributes are available to scour instances.

value

value

The raw value being wrapped. You can use this to terminate a chained call.

users =
  [ { name: 'john', admin: true },
    { name: 'kyle', admin: false } ]

scour(users)
  .filter({ admin: true })
  .value
// => [ { name: 'john', admin: true } ]

root

root

A reference to the root scour instance. Everytime you traverse using go(), a new scour object is spawned that's scoped to a keypath. Each of these scour objects have a root attribute that's a reference to the top-level scour object.

db = scour(...)

photos = db.go('photos')
photos.root    // => same as `db`

This allows you to return to the root when needed.

db = scour(...)
artist = db.go('artists', '9328')
artist.root.go('albums').find({ artist_id: artist.get('id') })

keypath

keypath

An array of strings representing each step in how deep the current scope is relative to the root. Each time you traverse using go(), a new scour object is spawned.

db = scour(...)

users = db.go('users')
users.keypath            // => ['users']

admins = users.go('admins')
admins.keypath           // => ['users', 'admins']

user = admins.go('23')
user.keypath             // => ['users', 'admins', '23']

Utility functions

These are utilities that don't need a wrapped object.

scour.get

scour.get(object, keypath)

Gets a keypath from an object.

data = { users: { bob: { name: 'john' } } }

result = get(data, ['users', 'bob', 'name'])
// => 'robert'

This is also available as require('scourjs/utilities/get').

scour.set

scour.set(object, keypath, value)

Sets a keypath into an object immutably.

data = { users: { bob: { name: 'john' } } }

result = set(data, ['users', 'bob', 'name'], 'robert')
// => { users: { bob: { name: 'robert' } } }

This is also available as require('scourjs/utilities/set').

scour.del

scour.del(object, keypath)

Deletes a keypath from an object immutably.

data = { users: { bob: { name: 'robert' } } }
result = del(data, ['users', 'bob', 'name'])

// => { users: { bob: {} } }

This is also available as require('scourjs/utilities/del').

scour.extendIn

scour.extendIn(object, keypath, extensions...)

Extends a keypath from an object immutably.

data = { users: { bob: { name: 'robert' } } }
result = extendIn(data, ['users', 'bob'], { email: '[email protected]' })

// => { users: { bob: { name: 'robert', email: '[email protected]' } } }

This is also available as require('scourjs/utilities/extend_in').

scour.each

scour.each(iterable, fn)

Iterates through iterable, either an object or an array. This is an implementation of Array#forEach that also works for objects. The callback fn will be invoked with two parameters: currentValue and key, just like Array#forEach.

This is also available as require('scourjs/utilities/each').

scour.map

scour.map(iterable, fn)

Creates a new Array with with the results of calling a provided function on every element in this array. Works like Array#map, but also works on objects as well as arrays.

The callback fn will be invoked with two parameters: currentValue and key, just like Array#map.

This is also available as require('scourjs/utilities/map').

scour.mapObject

scour.mapObject(iterable, fn)

Creates a new Object with with the results of calling a provided function on every element in this array. Works like Array#map, but also works on objects as well as arrays, and it returns an object instead.

The callback fn will be invoked with two parameters: currentValue and key, just like Array#map.

object = { a: 20, b: 30, c: 40 }
result = scour.mapObject(object, (val, key) => {
  return '$' + val + '.00'
})

// => { a: '$20.00', b: '$30.00', c: '$40.00' }

This is also available as require('scourjs/utilities/map_object').

scour.indexedMap

scour.indexedMap(iterable, fn)

Creates a new Object with with the results of calling a provided function returning the keys and values for the new object.

The callback fn will be invoked with two parameters: currentValue and key, just like Array#map.

The callback fn should return an array with two elements: with result[0] being the key, and result[1] being the value. These are what the new object will be constructed with.

The iterable parameter can be an object or an array. This works like Array#map, but also works on objects as well as arrays.

list = ['Fred', 'Barney', 'Wilma']

object = scour.indexedMap(list, (val, key) => {
  var newkey = val.substr(0, 1)
  return [ newkey, val ]
})

// => { f: 'Fred', b: 'Barney', w: 'Wilma' }

This is also available as require('scourjs/utilities/indexed_map').

scour.filter

scour.filter(iterable, function(val, key), [isArray])

Creates a new Array or Object with all elements that pass the test implemented by the provided function.

Works like Array#filter, but will return an object if an object is also passed.

The optional isArray argument, when passed true, will always make this return an Array. If false, it will always be an Object. Leave it undefined for the default behavior.

This is also available as require('scourjs/utilities/filter').

scour.sortBy

scour.sortBy(iterable, criteria)

Sorts by a given criteria.

list = [ { name: 'Fred' }, { name: 'Barney' }, { name: 'Wilma' } ]
scour.sortBy(list, 'name')

This is also available as require('scourjs/utilities/sort_by').

Thanks

scour © 2015+, Rico Sta. Cruz. Released under the MIT License.
Authored and maintained by Rico Sta. Cruz with help from contributors (list).

ricostacruz.com  ·  GitHub @rstacruz  ·  Twitter @rstacruz

More Repositories

1

nprogress

For slim progress bars like on YouTube, Medium, etc
JavaScript
25,552
star
2

cheatsheets

Cheatsheets for web development - devhints.io
SCSS
13,674
star
3

jquery.transit

Super-smooth CSS3 transformations and transitions for jQuery
JavaScript
7,328
star
4

rscss

Reasonable System for CSS Stylesheet Structure
3,894
star
5

flatdoc

Build sites fast from Markdown
CSS
2,679
star
6

webpack-tricks

Tips and tricks in using Webpack
2,359
star
7

sparkup

A parser for a condensed HTML format
Python
1,566
star
8

backbone-patterns

Common Backbone.js usage patterns.
760
star
9

remount

Mount React components to the DOM using custom elements
JavaScript
680
star
10

sinatra-assetpack

Package your assets transparently in Sinatra.
CSS
542
star
11

jsdom-global

Enable DOM in Node.js
JavaScript
472
star
12

hicat

Command-line syntax highlighter
JavaScript
405
star
13

kingraph

Plots family trees using JavaScript and Graphviz
JavaScript
390
star
14

vim-closer

Closes brackets
Vim Script
337
star
15

mocha-jsdom

Simple jsdom integration with mocha
JavaScript
254
star
16

css-condense

[unsupported] A CSS compressor that shows no mercy
JavaScript
206
star
17

swipeshow

The unassuming touch-enabled JavaScript slideshow
JavaScript
191
star
18

rsjs

Reasonable System for JavaScript Structure
181
star
19

vim-coc-settings

My Vim settings for setting it up like an IDE
Vim Script
164
star
20

startup-name-generator

Let's name your silly startup
JavaScript
164
star
21

onmount

Safe, reliable, idempotent and testable behaviors for DOM nodes
JavaScript
156
star
22

psdinfo

Inspect PSD files from the command line
JavaScript
147
star
23

vim-hyperstyle

Write CSS faster
Python
144
star
24

vim-from-scratch

Rico's guide for setting up Vim
144
star
25

js2coffee.py

JS to CoffeeScript compiler. [DEPRECATED]
Python
127
star
26

firefox-stealthfox

Firefox customization for stealth toolbars
CSS
122
star
27

mocha-clean

Clean up mocha stack traces
JavaScript
107
star
28

jquery-stuff

A collection of small jQuery trinkets
JavaScript
96
star
29

npm-pipeline-rails

Use npm as part of your Rails asset pipeline
Ruby
95
star
30

navstack

Manages multiple screens with mobile-friendly transitions
JavaScript
94
star
31

bootstrap-practices

List of practices when using Bootstrap in projects
90
star
32

details-polyfill

Polyfill for the HTML5 <details> element, no dependencies
JavaScript
89
star
33

dom101

DOM manipulation utilities
JavaScript
82
star
34

unorphan

Removes text orphans
JavaScript
81
star
35

expug

Pug templates for Elixir
Elixir
80
star
36

stylelint-rscss

Validate CSS with RSCSS conventions
JavaScript
74
star
37

feh-blur-wallpaper

Blur your desktop wallpaper when windows are open
Shell
73
star
38

pomo.js

Command-line timer, great for Pomodoros
JavaScript
73
star
39

sinatra-backbone

Neat Backbone.js integration with Sinatra.
Ruby
72
star
40

flowloop

A Pomodoro-like timer for hyper-productivity
JavaScript
71
star
41

vimfiles

My VIM config files.
Lua
63
star
42

bookmarks

My bookmarks
63
star
43

my_qmk_keymaps

Keymaps for keyboards
C
59
star
44

typish

Typewriter simulator
JavaScript
58
star
45

iconfonts

Fine-tuned icon fonts integration for Sass, Less and Stylus
CSS
54
star
46

pre.js

Efficient, resilient resource preloader for JS/CSS
JavaScript
54
star
47

tape-watch

Rerun tape tests when files change
JavaScript
53
star
48

tinkerbin

Tinkerbin.com
JavaScript
52
star
49

vim-fastunite

Search for files fast
Vim Script
48
star
50

collaborative-etiquette

A manifesto for happy Open Source projects
46
star
51

decca

Render interfaces using pure functions and virtual DOM
JavaScript
45
star
52

vim-opinion

My opinionated vim defaults
Vim Script
44
star
53

modern-development

Using agile methods to build quality web applications
CSS
43
star
54

til-2013

Old version of http://ricostacruz.com/til (2015-2018)
CSS
42
star
55

ion

[deprecated] Ruby/Redis search engine.
Ruby
41
star
56

timetip

Deliciously-minimal time tracker for the command-line
JavaScript
40
star
57

vim-xtract

Extract the selection into a new file
Vim Script
39
star
58

bump-cli

Command-line version incrementer
JavaScript
39
star
59

halla

Native Slack wrapper app without the bloat
JavaScript
38
star
60

newsreader-sample-layout

CSS
36
star
61

ento

Simple, stateful, observable objects in JavaScript
JavaScript
36
star
62

cron-scheduler

Runs jobs in periodic intervals
JavaScript
35
star
63

promise-conditional

Use if-then-else in promise chains
JavaScript
34
star
64

ractive-touch

Touch events for Ractive
JavaScript
33
star
65

jquery.unorphan

[deprecated] Obliterate text orphans.
JavaScript
33
star
66

git-update-ghpages

Simple tool to update GitHub pages
Shell
33
star
67

greader

[UNSUPPORTED] Google Reader API client for Ruby
Ruby
32
star
68

penpad

Design and document web UI components
TypeScript
32
star
69

typecat

TypeScript
31
star
70

react-meta-elements

Sets document title and meta tags using React elements or hooks
TypeScript
31
star
71

vim-ultisnips-css

[deprecated] Write CSS in VIM faster.
Ruby
31
star
72

tape-plus

Nested tape tests with before/after, async, and promise support
JavaScript
30
star
73

taskpaper.js

Taskpaper parser in JavaScript
JavaScript
28
star
74

frontend-starter-kit

Rico's opinionated Metalsmith frontend kit
JavaScript
28
star
75

homebrew-backup

Back up your Homebrew profile
Shell
28
star
76

fishfiles

my fish-shell config files
Shell
28
star
77

passwordgen.js

Password generator for the command line
JavaScript
28
star
78

reacco

Generate documentation from README files.
Ruby
26
star
79

ghub

Open this project in github
Shell
26
star
80

sass_icon_fonts

Sass 3.2 integration with modern icon fonts.
CSS
26
star
81

lidoc

[Deprecated] Literate-programming style documentation tool.
CoffeeScript
24
star
82

rspec-repeat

Repeats an RSpec example until it succeeds.
Ruby
24
star
83

lofi

VHS music machine from the 80's
JavaScript
24
star
84

sinatra-template

Ruby
24
star
85

fish-asdf

Fish shell integrations for asdf version manager
Shell
24
star
86

wiki

Stuff
23
star
87

arch-installer

Install UI for Arch Linux
Shell
22
star
88

slack-emoji-magic

Magic: the Gathering emojis
Makefile
21
star
89

node-hledger

Node.js API for hledger
JavaScript
21
star
90

ractive-promise-alt

Adaptor for Ractive.js to support promises
JavaScript
21
star
91

webpack-starter-kit

Baseline configuration for Webpack
JavaScript
21
star
92

vimbower

Use bower, git and pathogen to manage your vim setup
21
star
93

til-2020

Today I learned blog of @rstacruz
TypeScript
21
star
94

phoenix_expug

Expug integration for Phoenix
JavaScript
20
star
95

cssutils

Collection of Sass utility mixins and other goodies.
CSS
20
star
96

cdnjs-command

Command line helper for cdnjs.com
Ruby
20
star
97

responsive-modular-scale.css

Responsive typography using CSS variables
20
star
98

curlformat

CLI utility to clean up your "Copy as cURL" strings
JavaScript
19
star
99

ractive-loader

ractive template loader for webpack
JavaScript
19
star
100

ajaxapi

Minimal AJAX library for APIs. Supports promises
JavaScript
18
star