pipeline.ts   A
last analyzed

Complexity

Total Complexity 10
Complexity/F 2

Size

Lines of Code 81
Function Count 5

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 40
mnd 5
bc 5
fnc 5
dl 0
loc 81
rs 10
bpm 1
cpm 2
noi 0
c 0
b 0
f 0

5 Functions

Rating   Name   Duplication   Size   Complexity  
A Pipeline.send 0 9 1
A Pipeline.through 0 9 2
B Pipeline.then 0 34 5
A Pipeline.isPipeObject 0 8 1
A Pipeline.isPipeFunction 0 9 1
1
import {Pipe, PipeFunction, PipeObject} from "./types/pipes";
2
3
export class Pipeline<T> {
4
    private passable: T | null = null;
5
    private pipes: Pipe<T>[] = [];
6
7
    /**
8
     * Set the object being sent through the pipeline.
9
     * @param passable The data to be passed through the pipeline.
10
     * @returns {Pipeline<T>} The pipeline instance.
11
     */
12
    send(passable: T): this {
13
        this.passable = passable;
14
        return this;
15
    }
16
17
    /**
18
     * Set the array of pipes.
19
     * @param pipes The pipes to process the passable object.
20
     * @returns {Pipeline<T>} The pipeline instance.
21
     */
22
    through(pipes: Pipe<T>[] | Pipe<T>): this {
23
        this.pipes = Array.isArray(pipes) ? pipes : [pipes];
24
        return this;
25
    }
26
27
    /**
28
     * Execute the pipeline and resolve the final result.
29
     * @param destination The final operation after all pipes.
30
     * @returns {Promise<T>} The final processed result.
31
     */
32
    async then(destination: (value: T) => Promise<T>): Promise<T> {
33
        if (this.passable === null) {
34
            throw new Error('No passable object provided to the pipeline.');
35
        }
36
37
        if (!this.pipes.length) {
38
            return destination(this.passable);
39
        }
40
41
        // Reduce the pipes into a single composed function, handling next internally
42
        const pipeline = this.pipes.reduceRight(
43
            (next: (value: T) => Promise<T>, pipe: Pipe<T>) => {
44
                return async (passable: T): Promise<T> => {
45
                    if (this.isPipeFunction(pipe)) {
46
                        const result = await pipe(passable);
47
                        return next(result);
48
                    }
49
                    if (this.isPipeObject(pipe)) {
50
                        const result = await pipe.handle(passable);
51
                        return next(result);
52
                    }
53
                    throw new Error('Pipe must be a function or an object with a "handle" method.');
54
                };
55
            },
56
            destination
57
        );
58
59
        return pipeline(this.passable);
60
    }
61
62
63
    /**
64
     * Type guard to check if the pipe is a function.
65
     * @param pipe The pipe to check.
66
     * @returns {pipe is PipeFunction<T>} Whether the pipe is a function.
67
     */
68
    private isPipeFunction(pipe: Pipe<T>): pipe is PipeFunction<T> {
69
        return typeof pipe === 'function';
70
    }
71
72
    /**
73
     * Type guard to check if the pipe is an object with a handle method.
74
     * @param pipe The pipe to check.
75
     * @returns {pipe is PipeObject<T>} Whether the pipe is an object with a handle method.
76
     */
77
    private isPipeObject(pipe: Pipe<T>): pipe is PipeObject<T> {
78
        return typeof (pipe as PipeObject<T>).handle === 'function';
79
    }
80
}
81