- Add GETTING_STARTED.md with quick start guide and development modes - Add INSTALL.sh automated installation script - Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md - Add QUICK_REFERENCE.md for common commands - Add SETUP_GUIDE.md with detailed setup instructions - Update README.md with improved project overview - Add did-wallet app dependencies and node_modules
355 lines
8.7 KiB
TypeScript
355 lines
8.7 KiB
TypeScript
import { pushable } from 'it-pushable'
|
|
import merge from 'it-merge'
|
|
import type { Duplex, Transform, Sink } from 'it-stream-types'
|
|
|
|
interface SourceFn<A = any> { (): A }
|
|
|
|
type PipeSource<A = any> =
|
|
Iterable<A> |
|
|
AsyncIterable<A> |
|
|
SourceFn<A> |
|
|
Duplex<A, any, any>
|
|
|
|
type PipeTransform<A = any, B = any> =
|
|
Transform<A, B> |
|
|
Duplex<B, A>
|
|
|
|
type PipeSink<A = any, B = any> =
|
|
Sink<A, B> |
|
|
Duplex<any, A, B>
|
|
|
|
type PipeOutput<A> =
|
|
A extends Sink<any> ? ReturnType<A> :
|
|
A extends Duplex<any, any, any> ? ReturnType<A['sink']> :
|
|
never
|
|
|
|
// single item pipe output includes pipe source types
|
|
type SingleItemPipeOutput<A> =
|
|
A extends Iterable<any> ? A :
|
|
A extends AsyncIterable<any> ? A :
|
|
A extends SourceFn ? ReturnType<A> :
|
|
A extends Duplex<any, any, any> ? A['source'] :
|
|
PipeOutput<A>
|
|
|
|
type PipeFnInput<A> =
|
|
A extends Iterable<any> ? A :
|
|
A extends AsyncIterable<any> ? A :
|
|
A extends SourceFn ? ReturnType<A> :
|
|
A extends Transform<any, any> ? ReturnType<A> :
|
|
A extends Duplex<any, any, any> ? A['source'] :
|
|
never
|
|
|
|
// one item, just a pass-through
|
|
export function pipe<
|
|
A extends PipeSource
|
|
> (
|
|
source: A
|
|
): SingleItemPipeOutput<A>
|
|
|
|
// two items, source to sink
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeSink<PipeFnInput<A>>
|
|
> (
|
|
source: A,
|
|
sink: B
|
|
): PipeOutput<B>
|
|
|
|
// three items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeSink<PipeFnInput<B>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
sink: C
|
|
): PipeOutput<C>
|
|
|
|
// many items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeSink<PipeFnInput<C>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
sink: D
|
|
): PipeOutput<D>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeSink<PipeFnInput<D>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
sink: E
|
|
): PipeOutput<E>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeSink<PipeFnInput<E>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
sink: F
|
|
): PipeOutput<F>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeTransform<PipeFnInput<E>>,
|
|
G extends PipeSink<PipeFnInput<F>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
transform5: F,
|
|
sink: G
|
|
): PipeOutput<G>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeTransform<PipeFnInput<E>>,
|
|
G extends PipeTransform<PipeFnInput<F>>,
|
|
H extends PipeSink<PipeFnInput<G>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
transform5: F,
|
|
transform6: G,
|
|
sink: H
|
|
): PipeOutput<H>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeTransform<PipeFnInput<E>>,
|
|
G extends PipeTransform<PipeFnInput<F>>,
|
|
H extends PipeTransform<PipeFnInput<G>>,
|
|
I extends PipeSink<PipeFnInput<H>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
transform5: F,
|
|
transform6: G,
|
|
transform7: H,
|
|
sink: I
|
|
): PipeOutput<I>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeTransform<PipeFnInput<E>>,
|
|
G extends PipeTransform<PipeFnInput<F>>,
|
|
H extends PipeTransform<PipeFnInput<G>>,
|
|
I extends PipeTransform<PipeFnInput<H>>,
|
|
J extends PipeSink<PipeFnInput<I>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
transform5: F,
|
|
transform6: G,
|
|
transform7: H,
|
|
transform8: I,
|
|
sink: J
|
|
): PipeOutput<J>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeTransform<PipeFnInput<E>>,
|
|
G extends PipeTransform<PipeFnInput<F>>,
|
|
H extends PipeTransform<PipeFnInput<G>>,
|
|
I extends PipeTransform<PipeFnInput<H>>,
|
|
J extends PipeTransform<PipeFnInput<I>>,
|
|
K extends PipeSink<PipeFnInput<J>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
transform5: F,
|
|
transform6: G,
|
|
transform7: H,
|
|
transform8: I,
|
|
transform9: J,
|
|
sink: K
|
|
): PipeOutput<K>
|
|
|
|
// lots of items, source to sink with transform(s) in between
|
|
export function pipe<
|
|
A extends PipeSource,
|
|
B extends PipeTransform<PipeFnInput<A>>,
|
|
C extends PipeTransform<PipeFnInput<B>>,
|
|
D extends PipeTransform<PipeFnInput<C>>,
|
|
E extends PipeTransform<PipeFnInput<D>>,
|
|
F extends PipeTransform<PipeFnInput<E>>,
|
|
G extends PipeTransform<PipeFnInput<F>>,
|
|
H extends PipeTransform<PipeFnInput<G>>,
|
|
I extends PipeTransform<PipeFnInput<H>>,
|
|
J extends PipeTransform<PipeFnInput<I>>,
|
|
K extends PipeTransform<PipeFnInput<J>>,
|
|
L extends PipeSink<PipeFnInput<K>>
|
|
> (
|
|
source: A,
|
|
transform1: B,
|
|
transform2: C,
|
|
transform3: D,
|
|
transform4: E,
|
|
transform5: F,
|
|
transform6: G,
|
|
transform7: H,
|
|
transform8: I,
|
|
transform9: J,
|
|
transform10: K,
|
|
sink: L
|
|
): PipeOutput<L>
|
|
|
|
export function pipe (first: any, ...rest: any[]): any {
|
|
if (first == null) {
|
|
throw new Error('Empty pipeline')
|
|
}
|
|
|
|
// Duplex at start: wrap in function and return duplex source
|
|
if (isDuplex(first)) {
|
|
const duplex = first
|
|
first = () => duplex.source
|
|
// Iterable at start: wrap in function
|
|
} else if (isIterable(first) || isAsyncIterable(first)) {
|
|
const source = first
|
|
first = () => source
|
|
}
|
|
|
|
const fns = [first, ...rest]
|
|
|
|
if (fns.length > 1) {
|
|
// Duplex at end: use duplex sink
|
|
if (isDuplex(fns[fns.length - 1])) {
|
|
fns[fns.length - 1] = fns[fns.length - 1].sink
|
|
}
|
|
}
|
|
|
|
if (fns.length > 2) {
|
|
// Duplex in the middle, consume source with duplex sink and return duplex source
|
|
for (let i = 1; i < fns.length - 1; i++) {
|
|
if (isDuplex(fns[i])) {
|
|
fns[i] = duplexPipelineFn(fns[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
return rawPipe(...fns)
|
|
}
|
|
|
|
export const rawPipe = (...fns: any): any => {
|
|
let res
|
|
while (fns.length > 0) {
|
|
res = fns.shift()(res)
|
|
}
|
|
return res
|
|
}
|
|
|
|
const isAsyncIterable = (obj: any): obj is AsyncIterable<unknown> => {
|
|
return obj?.[Symbol.asyncIterator] != null
|
|
}
|
|
|
|
const isIterable = (obj: any): obj is Iterable<unknown> => {
|
|
return obj?.[Symbol.iterator] != null
|
|
}
|
|
|
|
const isDuplex = (obj: any): obj is Duplex => {
|
|
if (obj == null) {
|
|
return false
|
|
}
|
|
|
|
return obj.sink != null && obj.source != null
|
|
}
|
|
|
|
const duplexPipelineFn = (duplex: Duplex<any, any, any>) => {
|
|
return (source: any) => {
|
|
const p = duplex.sink(source)
|
|
|
|
if (p?.then != null) {
|
|
const stream = pushable<any>({
|
|
objectMode: true
|
|
})
|
|
p.then(() => {
|
|
stream.end()
|
|
}, (err: Error) => {
|
|
stream.end(err)
|
|
})
|
|
|
|
let sourceWrap: () => Iterable<any> | AsyncIterable<any>
|
|
const source = duplex.source
|
|
|
|
if (isAsyncIterable(source)) {
|
|
sourceWrap = async function * () {
|
|
yield * source
|
|
stream.end()
|
|
}
|
|
} else if (isIterable(source)) {
|
|
sourceWrap = function * () {
|
|
yield * source
|
|
stream.end()
|
|
}
|
|
} else {
|
|
throw new Error('Unknown duplex source type - must be Iterable or AsyncIterable')
|
|
}
|
|
|
|
return merge(stream, sourceWrap())
|
|
}
|
|
|
|
return duplex.source
|
|
}
|
|
}
|