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
6 import TaxReturn from './TaxReturn';
7 import * as Trace from './Trace';
8 import Form, { FormClass } from './Form';
10 export abstract class Line<T> {
11 private _description?: string;
13 _id: string; // _id is set by Form.init().
14 form: Form; // Set by Form.init();
16 constructor(description?: string) {
17 this._description = description;
24 get description(): string {
25 return this._description;
28 abstract value(tr: TaxReturn): T;
31 type ComputeFunc<T> = (tr: TaxReturn) => T;
33 export class ComputedLine<T> extends Line<T> {
34 private _compute: ComputeFunc<T>;
36 constructor(compute: ComputeFunc<T>, description?: string) {
38 this._compute = compute;
41 value(tr: TaxReturn): T {
43 const value = this._compute(tr);
49 export class ReferenceLine<F extends Form,
50 L extends keyof F['lines'],
51 T extends ReturnType<F['lines'][L]['value']>>
53 private _form: FormClass<F>;
55 private _fallback?: T;
57 // If creating a ReferenceLine and F is the same class as the
58 // the one the Line is in, erase |form|'s type with |as any| to
59 // keep TypeScript happy.
60 constructor(form: FormClass<F>, line: L, description?: string, fallback?: T) {
61 super(description || `Reference ${form.name}@${line}`);
64 this._fallback = fallback;
67 value(tr: TaxReturn): T {
69 const form: F = tr.findForm(this._form);
70 if (this._fallback !== undefined && !form) {
72 return this._fallback;
74 const value: T = form.getValue(tr, this._line);
80 export class InputLine<U = unknown, T extends keyof U = any> extends Line<U[T]> {
82 private _fallback: U[T];
86 constructor(input: T, description?: string, fallback?: U[T]) {
87 super(description || `Input from ${input}`);
89 this._fallback = fallback;
92 value(tr: TaxReturn): U[T] {
94 if (!this.form.hasInput(this._input) && this._fallback !== undefined) {
96 return this._fallback;
98 const value = this.form.getInput<T>(this._input);
104 export class AccumulatorLine<F extends Form,
105 L extends keyof F['lines']>
106 extends Line<number> {
107 private _form: FormClass<F>;
110 constructor(form: FormClass<F>, line: L, description?: string) {
111 super(description || `Accumulator ${form.name}@${line}`);
118 const forms: F[] = tr.findForms(this._form);
119 const value = sumLineOfForms(tr, forms, this._line);
125 export class UnsupportedLine extends Line<number> {
126 constructor(description?: string) {
127 super(description || 'Unsupported');
131 // Unsupported lines are deliberately omitted from Trace.
136 export function sumLineOfForms<F extends Form, L extends keyof F['lines']>(
137 tr: TaxReturn, forms: F[], line: L): number {
138 const reducer = (acc: number, curr: F) => acc + curr.getValue(tr, line);
139 return forms.reduce(reducer, 0);
142 export function sumFormLines<F extends Form, L extends keyof F['lines']>(
143 tr: TaxReturn, form: F, lines: L[]): number {
145 for (const line of lines)
146 value += form.getValue(tr, line);