Strongly type Form lines.
[ustaxlib.git] / src / Line.ts
1 import TaxReturn from './TaxReturn';
2 import Form from './Form';
3
4 export abstract class Line<T> {
5 private _id: string;
6 private _description?: string;
7
8 form: Form<any, any>;
9
10 constructor(id: string, description?: string) {
11 this._id = id;
12 this._description = description;
13 }
14
15 get id(): string {
16 return this._id;
17 }
18
19 get description(): string {
20 return this._description;
21 }
22
23 abstract value(tr: TaxReturn): T;
24 };
25
26 type ComputeFunc<T> = (tr: TaxReturn, l: ComputedLine<T>) => T;
27
28 export class ComputedLine<T> extends Line<T> {
29 private _compute: ComputeFunc<T>;
30
31 constructor(id: string, compute: ComputeFunc<T>, description?: string) {
32 super(id, description);
33 this._compute = compute;
34 }
35
36 value(tr: TaxReturn): T {
37 return this._compute(tr, this);
38 }
39 };
40
41 export class ReferenceLine<T> extends Line<T> {
42 private _form: string;
43 private _line: string;
44
45 constructor(id: string, form: string, line: string, description?: string) {
46 super(id, description || `Reference F${form}.L${line}`);
47 this._form = form;
48 this._line = line;
49 }
50
51 value(tr: TaxReturn): T {
52 return tr.getForm(this._form).getLine(this._line).value(tr);
53 }
54 };
55
56 export class InputLine<U = unknown, T extends keyof U = any> extends Line<U[T]> {
57 private _input: T;
58
59 form: Form<any, U>;
60
61 constructor(id: string, input: T, description?: string) {
62 super(id, description);
63 this._input = input;
64 }
65
66 value(tr: TaxReturn): U[T] {
67 return this.form.getInput<T>(this._input);
68 }
69 };
70
71 export class AccumulatorLine extends Line<number> {
72 private _form: string;
73 private _line: string;
74
75 constructor(id: string, form: string, line: string, description?: string) {
76 super(id, description || `Accumulator F${form}.L${line}`);
77 this._form = form;
78 this._line = line;
79 }
80
81 value(tr: TaxReturn): number {
82 const forms = tr.getForms(this._form);
83 const reducer = (acc: number, curr: Form<any>) => acc + (curr.getValue(tr, this._line) as number);
84 return forms.reduce(reducer, 0);
85 }
86 };