Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .babelrc

This file was deleted.

3 changes: 3 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"]
}
34 changes: 16 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
"scripts": {
"build": "webpack",
"danger": "duti",
"test": "babel-node ./node_modules/mocha/bin/_mocha --require ./test/init.js",
"test": "tsc && mocha --require @babel/polyfill --require ./test/init.js",
"test:watch": "chokidar 'src/*.js' 'test/*.js' -c 'npm t'",
"browser": "TEST_ENV=browser karma start karma.conf.js",
"browser:local": "karma start karma.conf.js",
"coverage": "nyc --require babel-core/register --require babel-polyfill --require ./test/init.js mocha test",
"cicoveralls": "nyc report --reporter=text-lcov --require babel-core/register --require babel-polyfill --require ./test/init.js mocha test | coveralls",
"cicoverage": "nyc --reporter=lcov --require babel-core/register --require babel-polyfill --require ./test/init.js mocha test --reporter json > test-results.json",
"coverage": "nyc --require @babel/polyfill --require ./test/init.js mocha test",
"cicoveralls": "nyc report --reporter=text-lcov --require @babel/polyfill --require ./test/init.js mocha test | coveralls",
"cicoverage": "nyc --reporter=lcov --require @babel/polyfill --require ./test/init.js mocha test --reporter json > test-results.json",
"lint": "eslint dangerfile.js src/*.js test/*.js",
"lint:ci": "npm run lint -- -o lint-results.json -f json",
"lint-fix": "eslint dangerfile.js src/*.js test/*.js --fix",
Expand All @@ -27,27 +27,24 @@
},
"license": "MIT",
"dependencies": {
"babel-polyfill": "^6.23.0",
"@babel/polyfill": "^7.8.3",
"lodash": "^4.17.4"
},
"babel": {
"presets": [
"env"
]
},
"prettier": {
"singleQuote": true,
"semi": false,
"trailingComma": "es5"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-cli": "^6.22.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.0.0",
"babel-loader": "^7.0.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.1",
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.6",
"@babel/node": "^7.8.4",
"@babel/preset-env": "^7.8.6",
"@babel/preset-typescript": "^7.8.3",
"@babel/register": "^7.8.6",
"@types/lodash": "^4.14.149",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.0.6",
"bluebird": "^3.5.0",
"chai": "^4.1.0",
"chai-as-promised": "^7.1.1",
Expand All @@ -70,11 +67,12 @@
"karma-webpack": "^3.0.0",
"mocha": "^6.2.2",
"mocha-lcov-reporter": "^1.2.0",
"nyc": "^12.0.1",
"nyc": "^15.0.0",
"prettier": "^1.7.4",
"read-pkg": "^5.2.0",
"sinon": "^7.5.0",
"sinon-chai": "^3.0.0",
"typescript": "^3.8.3",
"webpack": "^4.1.0",
"webpack-cli": "^3.0.0",
"write-pkg": "^4.0.0"
Expand Down
49 changes: 0 additions & 49 deletions src/function.js

This file was deleted.

117 changes: 117 additions & 0 deletions src/function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import _ from 'lodash/fp'

// ✓ maybeCall((a, b) => a + b, 1, 5)
// ✓ maybeCall(null, 1, 5)
// × maybeCall('d', 1, 5)
// × maybeCall(undefined, 1, 5)
// × maybeCall((a, b) => a + b, 1)
// × maybeCall((a, b) => a.concat(b), 3, [2, 3, 4])
export let maybeCall = <I extends any[], O>(
fn: ((...args: I) => O) | null,
...args: I
): O | false => (_.isFunction(fn) && fn ? fn(...args) : false)

// (fn, a, b) -> fn(a, b)
// ✓ callOrReturn((a, b) => a + b, 1, 5)
// × callOrReturn(null, 1, 5)
// × callOrReturn('d', 1, 5)
// × callOrReturn(undefined, 1, 5)
// × callOrReturn((a, b) => a + b, 1)
// × callOrReturn((a, b) => a.concat(b), 3, [2, 3, 4])
export let callOrReturn = <I extends any[], O>(
fn: (...args: I) => O,
...args: I
): ((...args: I) => O) | O => (_.isFunction(fn) ? fn(...args) : fn)

// (a, Monoid f) -> f[a] :: f a
export let boundMethod = (method: string, object: Object) => {
// NOTE its complex to define a type to ensure object has the key 'method'. Type
// can be made to be more strict in the future. For now we keep it loose.
// @ts-ignore implicit any
return object[method].bind(object)
}

// http://ramdajs.com/docs/#converge
type Many<T> = T | ReadonlyArray<T>
export let converge = <T>(
converger: Function,
branches: Many<(...args: any[]) => any>
) => (...args: any[]) => converger(_.over(branches)(...args))

// Example
// type P = { name: string; height: number }
// const isTallerThan: F<P, F<P, Boolean>> = p1 => p2 => p1.height > p2.height
// const fatherOf: F<P, P> = p => ({ name: 'Bob', height: 5.6 })
// const isShorterThanFather = comply(isTallerThan, fatherOf)
// ^^^^^^^^^^^^^^^^^^^
// inferred Boolean type
type F<I, O> = (i: I) => O
export let composeApply = <I, M, O>(f: F<M, F<I, O>>, g: F<I, M>) => (
x: I
): O => f(g(x))(x)

export let comply = composeApply

// Prettier version of `defer` the one from bluebird docs
export let defer = <T>(): {
resolve: F<T, null>
reject: F<Error, null>
promise: Promise<T>
} => {
let resolve
let reject
let promise: Promise<T> = new Promise((res, rej) => {
resolve = res
reject = rej
})

return {
// NOTE We know resolve and reject will be defined here,
// but Typescript is unsure. Use ts-ignore for now.
// @ts-ignore possibly undefined.
resolve,
// @ts-ignore possibly undefined.
reject,
promise,
}
}
// `_.debounce` for async functions, which require consistently returning a single promise for all queued calls

// const add1 = (a: number) => a + 1
// const f = debounceAsync(1000, add1)
// const o = f(40)
// ^
// inferred Promise<number>
export let debounceAsync = <I extends any[], O>(
n: number,
f: (...A: I) => O
): ((...A: I) => Promise<O>) => {
let deferred = defer<O>()
let debounced = _.debounce(n, (...args) => {
deferred.resolve(f(...args))
deferred = defer()
})
return (...args: any) => {
debounced(...args)
return deferred.promise
}
}

// TODO stronger types
let currier = (f: Function) => (...fns: any[]) =>
_.curryN(fns[0].length, f(...fns))

// (f1, f2, ...fn) -> f1Args1 -> f1Arg2 -> ...f1ArgN -> fn(f2(f1))
// let add = (x: number, y: number) => x + y
// let double = (x: number) => x * 2
// const addAndDouble = flurry(add, double)
// ✓ addAndDouble(1)(4)
// × addAndDouble(1, 4)
export let flurry = currier(_.flow)

// like _.overArgs, but on all args
export let mapArgs = _.curry(
(mapper: (value: any, index: number, array: any[]) => any, fn: Function) => (
...x: any[]
) => fn(...x.map(mapper))
)
5 changes: 5 additions & 0 deletions test/init.js
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
global.__VERSION__ = '1.0.0'

/**
* @babel/register does not load .ts files by default
*/
require('@babel/register')({ extensions: ['.js', '.jsx', '.ts', '.tsx'] })
19 changes: 19 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
// Target latest version of ECMAScript.
"target": "esnext",
// Search under node_modules for non-relative imports.
"moduleResolution": "node",
// Process & infer types from .js files.
"allowJs": true,
// Don't emit; allow Babel to transform files.
"noEmit": true,
// Enable strictest settings like strictNullChecks & noImplicitAny.
"strict": true,
// Disallow features that require cross-file information for emit.
"isolatedModules": true,
// Import non-ES modules as default imports.
"esModuleInterop": true
},
"include": ["src"]
}
7 changes: 5 additions & 2 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var webpack = require('webpack')
var packageMetadata = require('./package.json')
var libraryName = packageMetadata.name
var libraryVersion = packageMetadata.version
var outputFile = libraryName + '.js'
var outputFile = `${libraryName}.js`

module.exports = {
devtool: 'source-map',
Expand All @@ -16,10 +16,13 @@ module.exports = {
libraryTarget: 'umd',
globalObject: 'this',
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
test: /(\.jsx|\.js|\.ts)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
Expand Down