Add license information.
[ustaxlib.git] / src / core / Line.ts
1 // Copyright 2020 Blue Static <https://www.bluestatic.org>
2 // This program is free software licensed under the GNU General Public License,
3 // version 3.0. The full text of the license can be found in LICENSE.txt.
4 // SPDX-License-Identifier: GPL-3.0-only
5
6 import TaxReturn from './TaxReturn';
7 import Form, { FormClass } from './Form';
8
9 export abstract class Line<T> {
10 private _description?: string;
11
12 _id: string; // _id is set by Form.init().
13 form: Form<any, any>; // Set by Form.init();
14
15 constructor(description?: string) {
16 this._description = description;
17 }
18
19 get id(): string {
20 return this._id;
21 }
22
23 get description(): string {
24 return this._description;
25 }
26
27 abstract value(tr: TaxReturn): T;
28 };
29
30 type ComputeFunc<T> = (tr: TaxReturn) => T;
31
32 export class ComputedLine<T> extends Line<T> {
33 private _compute: ComputeFunc<T>;
34
35 constructor(compute: ComputeFunc<T>, description?: string) {
36 super(description);
37 this._compute = compute;
38 }
39
40 value(tr: TaxReturn): T {
41 return this._compute(tr);
42 }
43 };
44
45 export class ReferenceLine<F extends Form<any>,
46 L extends keyof F['lines'],
47 T extends ReturnType<F['lines'][L]['value']>>
48 extends Line<T> {
49 private _form: FormClass<F>;
50 private _line: L;
51 private _fallback?: T;
52
53 // If creating a ReferenceLine and F is the same class as the
54 // the one the Line is in, erase |form|'s type with |as any| to
55 // keep TypeScript happy.
56 constructor(form: FormClass<F>, line: L, description?: string, fallback?: T) {
57 super(description || `Reference F${form.name}.L${line}`);
58 this._form = form;
59 this._line = line;
60 this._fallback = fallback;
61 }
62
63 value(tr: TaxReturn): T {
64 const form: F = tr.findForm(this._form);
65 if (this._fallback !== undefined && !form)
66 return this._fallback;
67 const value: T = form.getValue(tr, this._line);
68 return value;
69 }
70 };
71
72 export class InputLine<U = unknown, T extends keyof U = any> extends Line<U[T]> {
73 private _input: T;
74 private _fallback: U[T];
75
76 form: Form<any, U>;
77
78 constructor(input: T, description?: string, fallback?: U[T]) {
79 super(description || `Input from ${input}`);
80 this._input = input;
81 this._fallback = fallback;
82 }
83
84 value(tr: TaxReturn): U[T] {
85 if (!this.form.hasInput(this._input) && this._fallback !== undefined)
86 return this._fallback;
87 return this.form.getInput<T>(this._input);
88 }
89 };
90
91 export class AccumulatorLine<F extends Form<any>,
92 L extends keyof F['lines']>
93 extends Line<number> {
94 private _form: FormClass<F>;
95 private _line: L;
96
97 constructor(form: FormClass<F>, line: L, description?: string) {
98 super(description || `Accumulator F${form}.L${line}`);
99 this._form = form;
100 this._line = line;
101 }
102
103 value(tr): number {
104 const forms: F[] = tr.findForms(this._form);
105 return sumLineOfForms(tr, forms, this._line);
106 }
107 };
108
109 export function sumLineOfForms<F extends Form<any>, L extends keyof F['lines']>(
110 tr: TaxReturn, forms: F[], line: L): number {
111 const reducer = (acc: number, curr: F) => acc + curr.getValue(tr, line);
112 return forms.reduce(reducer, 0);
113 }