Repository: plaid/async-problem
Branch: master
Commit: fb03d31bbcd9
Files: 32
Total size: 20.3 KB
Directory structure:
gitextract_xmvspb7n/
├── .eslintrc.json
├── .github/
│ └── CODEOWNERS
├── .gitignore
├── .npmrc
├── README.md
├── async.js
├── await.js
├── bluebird-promisell.js
├── callbacks-revenge.js
├── callbacks.js
├── common/
│ ├── exit0.js
│ ├── exit1.js
│ ├── join.js
│ ├── read-file-callback.js
│ ├── read-file-promise.js
│ ├── revengeutils.js
│ └── sanctuary.js
├── coroutines-bluebird.js
├── coroutines-co.js
├── futures.js
├── input/
│ ├── bar.txt
│ ├── baz.txt
│ ├── foo.txt
│ └── index.txt
├── most.js
├── node-streams.js
├── package.json
├── promises-pipe.js
├── promises.js
├── righto.js
├── synchronous.js
└── test
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"root": true,
"extends": ["./node_modules/sanctuary-style/eslint-es6.json"],
"parserOptions": {"ecmaVersion": 8},
"env": {"node": true},
"rules": {
"max-len": ["error", {"code": 79, "ignoreComments": true}]
}
}
================================================
FILE: .github/CODEOWNERS
================================================
# This is a CODEOWNERS file.
#
# Please consult https://help.github.com/articles/about-codeowners/
# for documentation.
# Plaid codeowners requirements.
* @plaid/developer-relations
================================================
FILE: .gitignore
================================================
/node_modules/
================================================
FILE: .npmrc
================================================
package-lock=false
================================================
FILE: README.md
================================================
# JavaScript has a problem
We like to say that JavaScript has a callback problem<sup>†</sup>.
This project considers various approaches to the following problem:
*Given a path to a directory containing an index file, __index.txt__, and
zero or more other files, read the index file (which contains one filename
per line), then read each of the files listed in the index concurrently,
concat the resulting strings (in the order specified by the index), and
write the result to stdout.*
*The program's exit code should be 0 if the entire operation is successful;
1 otherwise.*
All side effects must be isolated to the `main` function. Impure functions
may be defined at the top level but may only be invoked in `main`.
The solutions are best read in the following order:
- [__synchronous.js__](./synchronous.js)
- [__callbacks.js__](./callbacks.js)
- [__node-streams.js__](./node-streams.js)
- [__async.js__](./async.js)
- [__righto.js__](./righto.js)
- [__promises.js__](./promises.js)
- [__promises-pipe.js__](./promises-pipe.js)
- [__bluebird-promisell.js__](./bluebird-promisell.js)
- [__most.js__](./most.js)
- [__coroutines-co.js__](./coroutines-co.js)
- [__coroutines-bluebird.js__](./coroutines-bluebird.js)
- [__await.js__](./await.js)
- [__futures.js__](./futures.js)
- [__callbacks-revenge.js__](./callbacks-revenge.js)
The above ordering is suggested reading order only – not grade. Solutions are
graded on the following criteria:
- the size of `main` (smaller is better); and
- the degree to which the approach facilitates breaking the problem into
manageable subproblems.
---
† Perhaps in five years we'll be saying that JavaScript has a promise problem.
================================================
FILE: async.js
================================================
'use strict';
const async = require ('async');
const S = require ('sanctuary');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-callback');
const main = () => {
const path = join (process.argv[2]);
readFile (path ('index.txt')) ((err, data) => {
if (err != null) exit1 (err);
async.map (
S.map (path) (S.lines (data)),
(filename, callback) => readFile (filename) (callback),
(err, results) => {
if (err == null) exit0 (S.joinWith ('') (results)); else exit1 (err);
}
);
});
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: await.js
================================================
'use strict';
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// concatFiles :: (String -> String) -> Promise Error String
async function concatFiles(path) {
const index = await readFile (path ('index.txt'));
const filenames = S.map (path) (S.lines (index));
const results = await Promise.all (S.map (readFile) (filenames));
return S.joinWith ('') (results);
}
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: bluebird-promisell.js
================================================
'use strict';
const P = require ('bluebird-promisell');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// concatFiles :: (String -> String) -> Promise Error String
const concatFiles = path => {
// readFileRel :: String -> Promise Error String
const readFileRel = S.compose (readFile) (path);
// indexP :: Promise Error String
const indexP = readFileRel ('index.txt');
// filenamesP :: Promise Error (Array String)
const filenamesP = P.liftp1 (S.lines) (indexP);
// resultsP :: Promise Error (Array String)
const resultsP = P.liftp1 (P.traversep (readFileRel)) (filenamesP);
// (return value) :: Promise Error String
return P.liftp1 (S.joinWith ('')) (resultsP);
};
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: callbacks-revenge.js
================================================
'use strict';
const fs = require ('fs');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const {
Arr,
Fn,
Str,
Path,
NodeEither,
GenericEitherT,
Cont,
} = require ('./common/revengeutils');
const getpath = Path.combine (process.argv[2]);
// A monad for working with continuations that contain NodeEithers
// :: type NC r e x = GenericEither (Cont r) NodeEither e x
// :: = Cont r (NodeEither e x)
const NC = GenericEitherT (NodeEither) (Cont);
// Standard NodeJS APIs need a little massaging to be valid continuations
// - Callback must be a curried, final argument
// - Can only pass a single argument to callback (an [err, ...data] array is fine)
// :: Path -> NC () String String
const readFile = path => cb =>
fs.readFile (path, {encoding: 'utf8'}, (...args) => cb (args));
// Main
// :: String -> NC () String String
const readAllFiles = Fn.pipe ([
getpath, // :: Path
readFile, // :: NC () String String
NC.map (Str.lines), // :: NC () String [String]
NC.map (Arr.map (getpath)), // :: NC () String [Path]
NC.chain (Arr.traverse (NC) (readFile)), // :: NC () String [String]
NC.map (Str.join ('')), // :: NC () String String
]);
// :: NC () String String
const result = readAllFiles ('index.txt');
// Remember that:
// :: type NC r e x = Cont r (NodeEither e x)
// so...
// :: NC () String String = Cont () (NodeEither String String)
// :: = ((NodeEither String String) -> ()) -> ()
// :: NodeEither String String -> ⊥
const fork = NodeEither.match ({Left: exit1, Right: exit0});
const main = () => result (fork); // :: ()
main ();
================================================
FILE: callbacks.js
================================================
'use strict';
const S = require ('sanctuary');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-callback');
const main = () => {
const path = join (process.argv[2]);
readFile (path ('index.txt')) ((err, data) => {
if (err != null) exit1 (err);
const filenames = S.lines (data);
const $results = [];
let filesRead = 0;
filenames.forEach ((file, idx) => {
readFile (path (file)) ((err, data) => {
if (err != null) exit1 (err);
$results[idx] = data;
filesRead += 1;
if (filesRead === filenames.length) exit0 (S.joinWith ('') ($results));
});
});
});
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: common/exit0.js
================================================
'use strict';
module.exports = s => {
process.stdout.write (s);
process.exit (0);
};
================================================
FILE: common/exit1.js
================================================
'use strict';
module.exports = err => {
process.stderr.write (`${err}\n`);
process.exit (1);
};
================================================
FILE: common/join.js
================================================
'use strict';
const path = require ('path');
const S = require ('sanctuary');
// join :: String -> String -> String
module.exports = S.curry2 (path.join);
================================================
FILE: common/read-file-callback.js
================================================
'use strict';
const fs = require ('fs');
// readFile :: String -> ((Error?, String?) -> Undefined) -> Undefined
module.exports = filename => callback =>
fs.readFile (filename, {encoding: 'utf8'}, callback);
================================================
FILE: common/read-file-promise.js
================================================
'use strict';
const fs = require ('fs');
// readFile :: String -> Promise Error String
module.exports = filename =>
new Promise ((res, rej) => {
fs.readFile (filename, {encoding: 'utf8'}, (err, data) => {
if (err == null) res (data); else rej (err);
});
});
================================================
FILE: common/revengeutils.js
================================================
'use strict';
const path = require ('path');
const derivemonad = M => {
const {of, chain} = M;
const map = f => chain (x => of (f (x)));
const lift2 = f => mx => my =>
chain (x => chain (y => of (f (x) (y))) (my)) (mx);
return Object.assign ({map, lift2}, M);
};
const Arr = (() => {
const of = x => [x];
const map = f => x => x.map (f);
const foldl = f => z => xs => xs.reduce ((p, c) => f (p) (c), z);
const empty = [];
const append = a => b => [...a, ...b];
const sequence = A =>
foldl (A.lift2 (b => a => append (b) (of (a)))) (A.of (empty));
const traverse = A => f => xs => sequence (A) (map (f) (xs));
return {map, foldl, traverse};
}) ();
const Fn = (() => {
const id = x => x;
const compose = f => g => a => f (g (a));
const flip = f => x => y => f (y) (x);
const pipe = Arr.foldl (flip (compose)) (id);
return {id, compose, flip, pipe, '.': compose};
}) ();
const Str = (() => {
const trim = s => s.trim ();
const join = sep => arr => arr.join (sep);
const split = sep => s => s.split (sep);
const lines = Fn['.'] (split ('\n')) (trim);
return {split, lines, join, trim};
}) ();
const Path = (() => {
const combine = base => sub => path.join (base, sub);
return {combine};
}) ();
// An Either interpretation of Node style first-element-falsy arrays
// :: type NodeEither e d = [Maybe e, ...d]
const NodeEither = (() => {
const Left = l => [l];
const Right = (...r) => [null, ...r];
const match = ({Left, Right}) => ([e, ...x]) => e ? Left (e) : Right (...x);
return {Left, Right, match};
}) ();
// The GenericEitherT monad transformer
// :: type GenericEitherT e m l r = m (e l r)
const GenericEitherT = E => M => {
const {Left, Right, match} = E;
// :: x -> m (e l x)
const of = x => M.of (Right (x));
// :: (a -> m (e l b)) -> m (e l a) -> m (e l b)
const chain = f =>
Fn['.'] (M.chain) (match) ({
Left: l => M.of (Left (l)),
Right: f,
});
return derivemonad ({of, chain});
};
// The continuation monad
// :: type Cont r a = (a -> r) -> r
const Cont = (() => {
const of = x => cb => cb (x);
const chain = f => m => cb => m (x => f (x) (cb));
return derivemonad ({of, chain});
}) ();
module.exports = {Arr, Fn, Str, Path, NodeEither, GenericEitherT, Cont};
================================================
FILE: common/sanctuary.js
================================================
'use strict';
const FutureTypes = require ('fluture-sanctuary-types');
const S = require ('sanctuary');
const $ = require ('sanctuary-def');
// PromiseType :: Type
const PromiseType = $.NullaryType
('Promise')
('')
([])
(x => x != null && x.constructor === Promise);
module.exports = S.create ({
checkTypes: true,
env: S.env.concat (FutureTypes.env.concat ([PromiseType])),
});
================================================
FILE: coroutines-bluebird.js
================================================
'use strict';
const bluebird = require ('bluebird');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// concatFiles :: (String -> String) -> Promise Error String
const concatFiles = bluebird.coroutine (function* generator(path) {
const index = yield readFile (path ('index.txt'));
const filenames = S.map (path) (S.lines (index));
const results = yield bluebird.all (S.map (readFile) (filenames));
return S.joinWith ('') (results);
});
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: coroutines-co.js
================================================
'use strict';
const co = require ('co');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// concatFiles :: (String -> String) -> Promise Error String
const concatFiles = path =>
co (function* generator() {
const index = yield readFile (path ('index.txt'));
const filenames = S.map (path) (S.lines (index));
const results = yield Promise.all (S.map (readFile) (filenames));
return S.joinWith ('') (results);
});
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: futures.js
================================================
'use strict';
const fs = require ('fs');
const Future = require ('fluture');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const S = require ('./common/sanctuary');
// readFile :: String -> Future Error String
const readFile = S.flip (Future.encaseN2 (fs.readFile)) ({encoding: 'utf8'});
// readFilePar :: String -> ConcurrentFuture Error String
const readFilePar = S.compose (Future.Par) (readFile);
// concatFiles :: (String -> String) -> Future Error String
const concatFiles = path =>
S.pipe ([path, // :: String
readFile, // :: Future Error String
S.map (S.lines), // :: Future Error (Array String)
S.map (S.map (path)), // :: Future Error (Array String)
S.map (S.traverse (Future.Par) (readFilePar)), // :: Future Error (ConcurrentFuture Error (Array String))
S.chain (Future.seq), // :: Future Error (Array String)
S.map (S.joinWith (''))]) // :: Future Error String
('index.txt');
const main = () => {
concatFiles (join (process.argv[2]))
.fork (exit1, exit0);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: input/bar.txt
================================================
BAR
================================================
FILE: input/baz.txt
================================================
BAZ
================================================
FILE: input/foo.txt
================================================
FOO
================================================
FILE: input/index.txt
================================================
foo.txt
bar.txt
baz.txt
================================================
FILE: most.js
================================================
'use strict';
const most = require ('most');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// concatFiles :: (String -> String) -> Promise Error String
const concatFiles = path =>
most.fromPromise (readFile (path ('index.txt')))
.map (S.lines)
.map (S.map (path))
.map (S.map (readFile))
.map (Promise.all.bind (Promise))
.awaitPromises ()
.map (S.joinWith (''))
.reduce ((x, y) => x + y, '');
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: node-streams.js
================================================
'use strict';
const fs = require ('fs');
const miss = require ('mississippi');
const split = require ('split2');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-callback');
const main = () => {
const path = join (process.argv[2]);
let results;
miss.pipe (
fs.createReadStream (path ('index.txt')),
split (),
miss.parallel (123, (filename, cb) => readFile (path (filename)) (cb)),
miss.concat (data => { results = data; }),
err => { if (err != null) exit1 (err); else exit0 (results); }
);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: package.json
================================================
{
"name": "async-problem",
"private": true,
"scripts": {
"lint": "eslint -- \"**/*.js\"",
"test": "./test"
},
"dependencies": {
"async": "3.1.0",
"bluebird": "3.7.1",
"bluebird-promisell": "0.7.0",
"co": "4.6.0",
"fluture": "11.0.3",
"fluture-sanctuary-types": "4.1.1",
"mississippi": "4.0.0",
"most": "1.7.3",
"righto": "6.0.0",
"sanctuary": "2.0.0",
"sanctuary-def": "0.20.0",
"split2": "3.1.1"
},
"devDependencies": {
"eslint": "5.15.x",
"sanctuary-style": "3.0.0"
}
}
================================================
FILE: promises-pipe.js
================================================
'use strict';
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// then :: (a -> (b | Promise e b)) -> Promise e a -> Promise e b
const then = f => p => p.then (f);
// concatFiles :: (String -> String) -> Promise Error String
const concatFiles = path =>
S.pipe ([path,
readFile,
then (S.lines),
then (S.map (path)),
then (S.map (readFile)),
then (Promise.all.bind (Promise)),
then (S.joinWith (''))])
('index.txt');
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: promises.js
================================================
'use strict';
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = require ('./common/read-file-promise');
const S = require ('./common/sanctuary');
// concatFiles :: (String -> String) -> Promise Error String
const concatFiles = path =>
Promise.resolve ('index.txt')
.then (path)
.then (readFile)
.then (S.lines)
.then (S.map (path))
.then (S.map (readFile))
.then (Promise.all.bind (Promise))
.then (S.joinWith (''));
const main = () => {
concatFiles (join (process.argv[2]))
.then (exit0, exit1);
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: righto.js
================================================
'use strict';
const fs = require ('fs');
const righto = require ('righto');
const S = require ('sanctuary');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
// readFile :: String -> Righto String
const readFile = filename =>
righto (fs.readFile, filename, {encoding: 'utf8'});
// concatFiles :: (String -> String) -> Righto String
const concatFiles = path => {
const readFileRel = S.compose (readFile) (path);
const index = readFileRel ('index.txt');
const files = righto.sync (S.compose (S.map (readFileRel)) (S.lines), index);
return righto.sync (S.joinWith (''), righto.all (files));
};
const main = () => {
concatFiles
(join (process.argv[2]))
((err, data) => { if (err == null) exit0 (data); else exit1 (err); });
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: synchronous.js
================================================
'use strict';
const fs = require ('fs');
const S = require ('sanctuary');
const exit0 = require ('./common/exit0');
const exit1 = require ('./common/exit1');
const join = require ('./common/join');
const readFile = filename => {
try {
return fs.readFileSync (filename, {encoding: 'utf8'});
} catch (err) {
exit1 (err);
}
};
const main = () => {
const path = join (process.argv[2]);
S.pipe ([path,
readFile,
S.lines,
S.map (path),
S.map (readFile),
S.joinWith (''),
exit0])
('index.txt');
};
if (process.mainModule.filename === __filename) main ();
================================================
FILE: test
================================================
#!/usr/bin/env bash
passed="\033[0;32mpassed\033[0m\n"
failed="\033[0;31mfailed\033[0m\n"
test() {
local actual
local expected
printf "Testing \033[0;36m%s\033[0m...\n" "$1"
printf %s "- correct directory name... "
expected="$(printf "FOO\nBAR\nBAZ\n")"
if ! actual="$(node "$1" input)" ; then
printf "$failed"
elif [[ "$actual" == "$expected" ]] ; then
printf "$passed"
else
printf "$failed"
fi
printf %s "- incorrect directory name... "
expected="^Error: ENOENT[,:] .* 'XXX/index.txt'$"
if actual="$(node "$1" XXX 2>&1 1>/dev/null)" ; then
printf "$failed"
elif [[ $? != 1 ]] ; then
printf "$failed"
elif [[ "$actual" =~ $expected ]] ; then
printf "$passed"
else
printf "$failed"
fi
printf %s "- inaccurate index... "
rm -f -- input/baz.txt
expected="^Error: ENOENT[,:] .* 'input/baz.txt'$"
if actual="$(node "$1" input 2>&1 1>/dev/null)" ; then
printf "$failed"
elif [[ $? != 1 ]] ; then
printf "$failed"
elif [[ "$actual" =~ $expected ]] ; then
printf "$passed"
else
printf "$failed"
fi
git checkout -- input/baz.txt
echo
}
test synchronous.js
test callbacks.js
test node-streams.js
test async.js
test righto.js
test promises.js
test promises-pipe.js
test bluebird-promisell.js
test most.js
test coroutines-co.js
test coroutines-bluebird.js
test await.js
test futures.js
test callbacks-revenge.js
gitextract_xmvspb7n/ ├── .eslintrc.json ├── .github/ │ └── CODEOWNERS ├── .gitignore ├── .npmrc ├── README.md ├── async.js ├── await.js ├── bluebird-promisell.js ├── callbacks-revenge.js ├── callbacks.js ├── common/ │ ├── exit0.js │ ├── exit1.js │ ├── join.js │ ├── read-file-callback.js │ ├── read-file-promise.js │ ├── revengeutils.js │ └── sanctuary.js ├── coroutines-bluebird.js ├── coroutines-co.js ├── futures.js ├── input/ │ ├── bar.txt │ ├── baz.txt │ ├── foo.txt │ └── index.txt ├── most.js ├── node-streams.js ├── package.json ├── promises-pipe.js ├── promises.js ├── righto.js ├── synchronous.js └── test
SYMBOL INDEX (1 symbols across 1 files)
FILE: await.js
function concatFiles (line 11) | async function concatFiles(path) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (23K chars).
[
{
"path": ".eslintrc.json",
"chars": 229,
"preview": "{\n \"root\": true,\n \"extends\": [\"./node_modules/sanctuary-style/eslint-es6.json\"],\n \"parserOptions\": {\"ecmaVersion\": 8}"
},
{
"path": ".github/CODEOWNERS",
"chars": 183,
"preview": "# This is a CODEOWNERS file.\n#\n# Please consult https://help.github.com/articles/about-codeowners/\n# for documentation.\n"
},
{
"path": ".gitignore",
"chars": 15,
"preview": "/node_modules/\n"
},
{
"path": ".npmrc",
"chars": 19,
"preview": "package-lock=false\n"
},
{
"path": "README.md",
"chars": 1713,
"preview": "# JavaScript has a problem\n\nWe like to say that JavaScript has a callback problem<sup>†</sup>.\nThis project considers va"
},
{
"path": "async.js",
"chars": 761,
"preview": "'use strict';\n\nconst async = require ('async');\nconst S = require ('sanctuary');\n\nconst exit0 "
},
{
"path": "await.js",
"chars": 737,
"preview": "'use strict';\n\nconst exit0 = require ('./common/exit0');\nconst exit1 = require ('./common/exit1');\nconst"
},
{
"path": "bluebird-promisell.js",
"chars": 1084,
"preview": "'use strict';\n\nconst P = require ('bluebird-promisell');\n\nconst exit0 = require ('./common/exit0');\n"
},
{
"path": "callbacks-revenge.js",
"chars": 1765,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\nconst exit0 = require ('./common/exit0');\nconst exit1 = require ('./common/ex"
},
{
"path": "callbacks.js",
"chars": 849,
"preview": "'use strict';\n\nconst S = require ('sanctuary');\n\nconst exit0 = require ('./common/exit0');\nconst exi"
},
{
"path": "common/exit0.js",
"chars": 90,
"preview": "'use strict';\n\nmodule.exports = s => {\n process.stdout.write (s);\n process.exit (0);\n};\n"
},
{
"path": "common/exit1.js",
"chars": 101,
"preview": "'use strict';\n\nmodule.exports = err => {\n process.stderr.write (`${err}\\n`);\n process.exit (1);\n};\n"
},
{
"path": "common/join.js",
"chars": 180,
"preview": "'use strict';\n\nconst path = require ('path');\n\nconst S = require ('sanctuary');\n\n// join :: String"
},
{
"path": "common/read-file-callback.js",
"chars": 223,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\n// readFile :: String -> ((Error?, String?) -> Undefined) -> Unde"
},
{
"path": "common/read-file-promise.js",
"chars": 290,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\n// readFile :: String -> Promise Error String\nmodule.exports = fi"
},
{
"path": "common/revengeutils.js",
"chars": 2295,
"preview": "'use strict';\n\nconst path = require ('path');\n\n\nconst derivemonad = M => {\n const {of, chain} = M;\n\n const map = f => "
},
{
"path": "common/sanctuary.js",
"chars": 423,
"preview": "'use strict';\n\nconst FutureTypes = require ('fluture-sanctuary-types');\nconst S = require ('sanctuary');\nc"
},
{
"path": "coroutines-bluebird.js",
"chars": 820,
"preview": "'use strict';\n\nconst bluebird = require ('bluebird');\n\nconst exit0 = require ('./common/exit0');\nconst exit"
},
{
"path": "coroutines-co.js",
"chars": 813,
"preview": "'use strict';\n\nconst co = require ('co');\n\nconst exit0 = require ('./common/exit0');\nconst exit1 "
},
{
"path": "futures.js",
"chars": 1455,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\nconst Future = require ('fluture');\n\nconst exit0 = "
},
{
"path": "input/bar.txt",
"chars": 4,
"preview": "BAR\n"
},
{
"path": "input/baz.txt",
"chars": 4,
"preview": "BAZ\n"
},
{
"path": "input/foo.txt",
"chars": 4,
"preview": "FOO\n"
},
{
"path": "input/index.txt",
"chars": 24,
"preview": "foo.txt\nbar.txt\nbaz.txt\n"
},
{
"path": "most.js",
"chars": 792,
"preview": "'use strict';\n\nconst most = require ('most');\n\nconst exit0 = require ('./common/exit0');\nconst exit1 "
},
{
"path": "node-streams.js",
"chars": 763,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\nconst miss = require ('mississippi');\nconst split "
},
{
"path": "package.json",
"chars": 552,
"preview": "{\n \"name\": \"async-problem\",\n \"private\": true,\n \"scripts\": {\n \"lint\": \"eslint -- \\\"**/*.js\\\"\",\n \"test\": \"./test\""
},
{
"path": "promises-pipe.js",
"chars": 865,
"preview": "'use strict';\n\nconst exit0 = require ('./common/exit0');\nconst exit1 = require ('./common/exit1');\nconst"
},
{
"path": "promises.js",
"chars": 719,
"preview": "'use strict';\n\nconst exit0 = require ('./common/exit0');\nconst exit1 = require ('./common/exit1');\nconst"
},
{
"path": "righto.js",
"chars": 945,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\nconst righto = require ('righto');\nconst S = re"
},
{
"path": "synchronous.js",
"chars": 697,
"preview": "'use strict';\n\nconst fs = require ('fs');\n\nconst S = require ('sanctuary');\n\nconst exit0 "
},
{
"path": "test",
"chars": 1421,
"preview": "#!/usr/bin/env bash\n\npassed=\"\\033[0;32mpassed\\033[0m\\n\"\nfailed=\"\\033[0;31mfailed\\033[0m\\n\"\n\ntest() {\n local actual\n lo"
}
]
About this extraction
This page contains the full source code of the plaid/async-problem GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (20.3 KB), approximately 6.3k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.