') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - brainrake/fuc: Functional Utilities for Coffeescript and Javascript · GitHub
Skip to content

Latest commit

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Functional Utilities for Coffeescript and Javascript

Underscore/lodash too much but never enough?

So you have async for breaking all your Promises?

Fuc it all!

> npm install fuc
require('fuc')._it_all() # fuc the global namespace, fuc prototypes1+__2# logs 2, returns 3unite {a:1}, {b:2} # => {a: 1, b: 2}dothus {a:1}, ->this.a+1# => 2
[1, 2, 4]._fap (it) ->if it%2thennullelse it-2# => [0, 2]

Also, fuc the browser (TODO)

> bower install fuc
<scriptsrc='bower_components/fuc/fuc.min.js'></script><script>Fuc._it_all()</script>

If you think that looks dangerous, you can fuc less but stay safe:

{__, fap, thus, unite} =require'fuc'

Srsly? Why?

Yes. lodash is nice, but functions aren't curried, and some are sorely missing (like flip).

So, here's a bundle of functions, in all its 22-line glory, that most of the time obviates the need to include helper libraries, for me at least.

I'll add some async helpers as well, I promise!

Documentation

Use the source!

Also see some examples.

curry: (Function) ->Functionfunction._curry:()->Function# takes a function with two or more arguments, returns a function that can# be called either with two or more arguments (same as the original),# or with one argument, in which case it returns a function that awaits# the second argument and possibly more - ultimate flexibilityisO: (value) ->Booleanvalue._isO:()->Boolean# returns true if value is not a primitivepp: (value) ->Stringvalue._pp:()->String# toString primitives; JSON.stringify and indent objects__: (arg [, args...]) -> arg
arg.__: ([args...]) -> arg
# console.log all arguments, return the first one; uses pp___: (prefix, arg [, args...]) -> arg
arg.___: (prefix [, args...]) -> arg
# console.log prefix and all args, return first arg (after prefix); uses ppflip: (Function(a, b [, c...])) ->Function(b, a [, c...])
function(a, b [, c...])._flip:()->Function(b, a [, c...])
# takes a function with two or more arguments, returns it with the first two# arguments flipped, and curriedflap: (arg, Function [, args...]) -> result
obj._flap: (Function [, args...]) -> result
# applies the function to the argument(s); `flip apply`dnib: (this_object, Function) ->Functionthis_object._dnib: (Function) ->Function# bind the `this` object in the function body; flipped `Function.bind`unite: (Object1, Object2 [, Objects...]) ->Objectobject1._unite: (Object2 [, Objects...]) ->Object# create a new object with properties merged from all the argumentsmaf: (Function, Array) ->Arrayarray._maf: (Function) ->Array# map, then filter out undefineds and nulls (but not `false`s, `0`s or ''s)zop: (Array) ->Objectarray._zop:()->Object# create an object from a list of pairs of [key, value]

All functions with two or more arguments can be used in a curried fashion: If you call them with only one argument, they will return a function awaiting the other argument (and any optional arguments).

Prototypes of built-in objects like Object and Array are only extended if you call Fuc._it_all(), and the new methods always start with an underscore to avoid name clashes.

Motivating Examples

__

I'm not saying we're stuck with console.log debugging in javascript. But it's the easiest, and yields the most results for the effort. Inspecting runtime values is much more important than in static languages: where proper languages throw errors, Javascript does something stupid and moves on like nothing happened. So you need to trace expressions' values to see what's going on. You could do that by setting breakpoints and watches, but that stops program execution and you need to muck about in Developer Tools. It's not so straightforward in node.js.

Logging could be more convenient though. When you want to log a subexpression, you have to copy it, since console.log doesn't return anything. Also, it's kind of boring to type it all the time. Well, that's fixed now, just insert __ wherever, and add parens as needed.

Array(16).join(__'here'-1) +'Fapman'# logs 'NaN'

To log extra information, use ___

fs.readFile (___'reading') 'file.txt'# logs 'reading file.txt'

I used to include the definition for __ at the top of every single Coffeescript/Javascript source file I wrote, plus usually a few of the other functions here. Now I don't have to.

unite

Lodash and jQuery have extend. It's why I include lodash most of the time (along with zipObject). But it mutates the argument. Bleah.

flap

So you want to write the argument first, and then the function you to call with it. Coffeescript has do which calls the function immediately after it, and passes the arguments with the same name as the function arguments.

Sometimes you need more though.

fap

Filter map. or f(x) for x in arr when f(x) not in [null, undefined].

License

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, for any purpose, commercial or non-commercial.

About

Functional Utilities for Coffeescript and Javascript

Resources

Stars

7 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages