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