diff --git a/.circleci/config.yml b/.circleci/config.yml index 5cba4bad..8fb640f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,7 @@ jobs: name: Install Local JavaScript Dependencies command: | nvm use default - npm install + npm install --legacy-peer-deps # Store a cache of local JavaScript modules. - save_cache: @@ -111,7 +111,7 @@ jobs: name: Install Local JavaScript Dependencies command: | nvm use node - npm install + npm install --legacy-peer-deps # Store a cache of local JavaScript modules. - save_cache: diff --git a/packages/core-fl/.eslintignore b/packages/core-fl/.eslintignore new file mode 100644 index 00000000..e99d5119 --- /dev/null +++ b/packages/core-fl/.eslintignore @@ -0,0 +1,9 @@ +node_modules/ +.git/ +.idea/ +examples/ +benchmark/ +experiments/ +perf/ +test/perf/ +dist/ diff --git a/packages/core-fl/package.json b/packages/core-fl/package.json new file mode 100644 index 00000000..7574500e --- /dev/null +++ b/packages/core-fl/package.json @@ -0,0 +1,41 @@ +{ + "author": "seemann@visisoft.de", + "description": "Fantasy-Land Api for @most/core", + "exports": { + ".": { + "import": "./dist/index.es.js", + "require": "./dist/index.js" + } + }, + "files": [ + "type-definitions", + "dist" + ], + "license": "MIT", + "main": "dist/index.js", + "module": "dist/index.es.js", + "name": "@most/core-fl", + "scripts": { + "build:dist": "rollup -c", + "test": "mocha --require ts-node/register ./test/*test**" + }, + "type": "module", + "version": "1.0.0", + "dependencies": { + "@most/disposable": "^1.3.0", + "@most/prelude": "^1.8.0", + "@most/scheduler": "^1.3.0", + "@most/types": "^1.1.0" + }, + "devDependencies": { + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", + "@types/ramda": "^0.29.10", + "fp-ts": "^2.16.2", + "mocha": "^10.3.0", + "ramda": "^0.29.1", + "rollup": "^4.10.0", + "rollup-plugin-typescript2": "^0.36.0", + "typescript": "^5.3.3" + } +} diff --git a/packages/core-fl/rollup.config.js b/packages/core-fl/rollup.config.js new file mode 100644 index 00000000..d82ce386 --- /dev/null +++ b/packages/core-fl/rollup.config.js @@ -0,0 +1,37 @@ +// import typescript from '@rollup/plugin-typescript' +import typescript from 'rollup-plugin-typescript2' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import pkg from './package.json' assert { type: 'json' } + +export default { + input: 'src/index.ts', + plugins: [ + nodeResolve({ + extensions: ['.mjs', '.js', '.json', '.node'] + }), + typescript() + ], + external: [ + '@most/scheduler', + '@most/disposable', + '@most/prelude' + ], + output: [ + { + file: pkg.main, + format: 'umd', + name: 'mostCoreFl', + sourcemap: true, + globals: { + '@most/scheduler': 'mostScheduler', + '@most/disposable': 'mostDisposable', + '@most/prelude': 'mostPrelude' + } + }, + { + file: pkg.module, + format: 'es', + sourcemap: true + } + ] +} diff --git a/packages/core-fl/src/FantasyLandStream.ts b/packages/core-fl/src/FantasyLandStream.ts new file mode 100644 index 00000000..2caec25b --- /dev/null +++ b/packages/core-fl/src/FantasyLandStream.ts @@ -0,0 +1,58 @@ +import { Stream, Sink, Scheduler, Disposable } from '@most/types' +import { + continueWith, + empty, + filter, + map, + ap, + now, + chain, + never +} from '../../core' + +interface FunctorFantasyLand { + ['fantasy-land/map'](fn: (a: A) => B): FunctorFantasyLand +} + +export const fantasyLand = (stream: Stream): FantasyLandStream => + new FantasyLandStream(stream) + +export class FantasyLandStream implements Stream, FunctorFantasyLand { + constructor(private readonly stream: Stream) {} + + run(sink: Sink, scheduler: Scheduler): Disposable { + return this.stream.run(sink, scheduler) + } + + ['fantasy-land/concat'](nextStream: Stream): FantasyLandStream { + return fantasyLand(continueWith(() => nextStream, this.stream)) + } + + ['fantasy-land/empty']() { + return fantasyLand(empty()) + } + + ['fantasy-land/filter'](predicate: (value: A) => boolean) { + return fantasyLand(filter(predicate, this.stream)) + } + + ['fantasy-land/map'](fn: (value: A) => B): FantasyLandStream { + return fantasyLand(map(fn, this.stream)) + } + + ['fantasy-land/ap'](mapper: Stream<(value: A) => B>) { + return fantasyLand(ap(mapper, this.stream)) + } + + ['fantasy-land/of'](value: B) { + return fantasyLand(now(value)) + } + + ['fantasy-land/chain'](fn: (value: A) => Stream) { + return fantasyLand(chain(fn, this.stream)) + } + + ['fantasy-land/zero']() { + return fantasyLand(never()) + } +} diff --git a/packages/core-fl/src/index.ts b/packages/core-fl/src/index.ts new file mode 100644 index 00000000..183d9318 --- /dev/null +++ b/packages/core-fl/src/index.ts @@ -0,0 +1,22 @@ +import { fantasyLand, FantasyLandStream } from './FantasyLandStream' +import { compose, curry2 } from '@most/prelude' +import { Stream } from '@most/types' + +import { periodic as _periodic, take as _take, tap as _tap } from '../../core/src' + +export const periodic = compose(fantasyLand, _periodic) + +interface Take { + (n: number, s: Stream): FantasyLandStream + (n: number): (s: Stream) => FantasyLandStream +} +export const take: Take = curry2((x, y) => fantasyLand(_take(x, y))) + +interface Tap { + (f: (a: A) => any, s: Stream): FantasyLandStream + (f: (a: A) => any): (s: Stream) => FantasyLandStream +} +export const tap: Tap = curry2((x, y) => fantasyLand(_tap(x, y))) + +export { fantasyLand, FantasyLandStream } +export { runEffects } from '../../core' diff --git a/packages/core-fl/test/fantasy-land-test.ts b/packages/core-fl/test/fantasy-land-test.ts new file mode 100644 index 00000000..9ccc5cd7 --- /dev/null +++ b/packages/core-fl/test/fantasy-land-test.ts @@ -0,0 +1,35 @@ +import { describe, it } from 'mocha' +import { assert } from '@briancavalier/assert' +import { newDefaultScheduler } from '@most/scheduler' +import { Stream } from '@most/types' + +import { periodic, runEffects, take, tap, FantasyLandStream } from '../src/index' +import { pipe } from 'fp-ts/function' +import { map as mapR } from 'ramda' + +const map = mapR as unknown as (fn: (x: A) => B) => (functor: FantasyLandStream) => FantasyLandStream + +const defaultScheduler = newDefaultScheduler() +const runEff = (s: Stream): Promise => runEffects(s, defaultScheduler) + +describe('fantasy-land', function () { + // const x = [0, 1, 2, 3] + // const sampleError = new Error('sample error') + + it('the types should line up', function () { + return runEff(take(2, periodic(10))) + .then(res => { + assert(typeof res === 'undefined') + }) + }) + + it('map', () => pipe( + periodic(10), + take(2), + map(() => 'foo'), + tap(x => { + assert(x === 'foo') + }), + runEff + )) +}) diff --git a/packages/core-fl/tsconfig.json b/packages/core-fl/tsconfig.json new file mode 100644 index 00000000..1bee471d --- /dev/null +++ b/packages/core-fl/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "declarationDir": "./dist", + "target": "ES2020" + }, + "extends": "../../tsconfig", + "include": [ + "src", + "test" + ] +} diff --git a/packages/core/src/combinator/continueWith.ts b/packages/core/src/combinator/continueWith.ts index 311f2a9d..e334b893 100644 --- a/packages/core/src/combinator/continueWith.ts +++ b/packages/core/src/combinator/continueWith.ts @@ -60,7 +60,7 @@ class ContinueWithSink extends Pipe implements Sink, Disposab try { this.disposable = this.continue(this.f, t, sink) } catch (e) { - sink.error(t, e) + sink.error(t, e as Error) } } diff --git a/packages/core/src/combinator/errors.ts b/packages/core/src/combinator/errors.ts index 17e6bf59..c4817485 100644 --- a/packages/core/src/combinator/errors.ts +++ b/packages/core/src/combinator/errors.ts @@ -90,7 +90,7 @@ class RecoverWithSink implements Sink, Disposable { try { this.disposable = this._continue(this.f, t, x, sink) } catch (e) { - sink.error(t, e) + sink.error(t, e as Error) } } diff --git a/packages/core/src/combinator/mergeConcurrently.ts b/packages/core/src/combinator/mergeConcurrently.ts index dd2c1eea..d498f963 100644 --- a/packages/core/src/combinator/mergeConcurrently.ts +++ b/packages/core/src/combinator/mergeConcurrently.ts @@ -72,7 +72,7 @@ class Outer implements Sink, Disposable { try { this.initInner(t, x) } catch (e) { - this.error(t, e) + this.error(t, e as Error) } } diff --git a/packages/core/src/runEffects.ts b/packages/core/src/runEffects.ts index 23dcf771..39934da3 100644 --- a/packages/core/src/runEffects.ts +++ b/packages/core/src/runEffects.ts @@ -56,7 +56,7 @@ function tryDispose (error: (e: Error) => void, end: (x: X) => void, x: X, di try { disposable.dispose() } catch (e) { - error(e) + error(e as Error) return } diff --git a/packages/core/src/source/tryEvent.ts b/packages/core/src/source/tryEvent.ts index 30aea744..c2e29fc3 100644 --- a/packages/core/src/source/tryEvent.ts +++ b/packages/core/src/source/tryEvent.ts @@ -8,7 +8,7 @@ export function tryEvent (t: Time, x: A, sink: Sink): void { try { sink.event(t, x) } catch (e) { - sink.error(t, e) + sink.error(t, e as Error) } } @@ -16,6 +16,6 @@ export function tryEnd(t: Time, sink: Sink): void { try { sink.end(t) } catch (e) { - sink.error(t, e) + sink.error(t, e as Error) } } diff --git a/packages/core/src/task.ts b/packages/core/src/task.ts index 9bbe31c5..cca285b1 100644 --- a/packages/core/src/task.ts +++ b/packages/core/src/task.ts @@ -15,6 +15,6 @@ export function runTask (task: DeferrableTask): E | A { try { return task.run() } catch (e) { - return task.error(e) + return task.error(e as Error) } }