Passed
Pull Request — main (#1)
by ABRAHAM
02:54
created

Pipeline   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 37
dl 0
loc 75
c 0
b 0
f 0
rs 10

5 Functions

Rating   Name   Duplication   Size   Complexity  
B then 0 32 5
A send 0 9 1
A through 0 9 2
A isPipeObject 0 8 1
A 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
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
                        return pipe(passable, next);
47
                    }
48
                    if (this.isPipeObject(pipe)) {
49
                        return pipe.handle(passable, next);
50
                    }
51
                    throw new Error('Pipe must be a function or an object with a "handle" method.');
52
                };
53
            },
54
            destination
55
        );
56
57
        return pipeline(this.passable);
58
    }
59
60
61
    /**
62
     * Type guard to check if the pipe is a function.
63
     * @param pipe The pipe to check.
64
     * @returns {pipe is PipeFunction<T>} Whether the pipe is a function.
65
     */
66
    private isPipeFunction(pipe: Pipe<T>): pipe is PipeFunction<T> {
67
        return typeof pipe === 'function';
68
    }
69
70
    /**
71
     * Type guard to check if the pipe is an object with a handle method.
72
     * @param pipe The pipe to check.
73
     * @returns {pipe is PipeObject<T>} Whether the pipe is an object with a handle method.
74
     */
75
    private isPipeObject(pipe: Pipe<T>): pipe is PipeObject<T> {
76
        return typeof (pipe as PipeObject<T>).handle === 'function';
77
    }
78
}
79