Move input from a TaxReturn to a Form.
authorRobert Sesek <rsesek@bluestatic.org>
Tue, 18 Feb 2020 05:18:16 +0000 (00:18 -0500)
committerRobert Sesek <rsesek@bluestatic.org>
Tue, 18 Feb 2020 05:18:16 +0000 (00:18 -0500)
This also associates every Line to a Form.

src/Form.test.ts
src/Form.ts
src/Line.test.ts
src/Line.ts
src/TaxReturn.test.ts
src/TaxReturn.ts

index d3f2f6f0aa16603d3a5179f7210e30ca63e7a8de..795fd850fab9dac7c210eab37aed3866f81853e2 100644 (file)
@@ -51,3 +51,32 @@ test('add duplicate line', () => {
 
   expect(() => new TestForm()).toThrow(InconsistencyError);
 });
+
+test('add line to two forms', () => {
+  const l = new ComputedLine<string>('bad', () => 'bad');
+
+  class TestForm1 extends Form {
+    get name(): string { return '1'; }
+
+    protected getLines() { return [ l ]; }
+  };
+  class TestForm2 extends Form {
+    get name(): string { return '2'; }
+
+    protected getLines() { return [ l ]; }
+  };
+
+  const f1 = new TestForm1();
+  expect(() => new TestForm2()).toThrow(InconsistencyError);
+});
+
+test('input', () => {
+  class TestForm extends Form {
+    get name() { return '1040'; }
+
+    protected getLines() { return []; }
+  };
+  const f = new TestForm({ 'Filing Status': 'S' });
+  expect(f.getInput('Filing Status')).toBe('S');
+  expect(() => f.getInput('Unknown')).toThrow(NotFoundError);
+});
index 7b9bf07cda3c7c18a43a22b3a5e7490c1b631779..e63829454d43f7694e57f12b2dacd9b786a059fa 100644 (file)
@@ -3,10 +3,12 @@ import { InconsistencyError, NotFoundError } from './Errors';
 
 export default abstract class Form {
   private _lines: Line<any>[] = [];
+  private _input?: object;
 
   abstract get name(): string;
 
-  constructor() {
+  constructor(input?: object) {
+    this._input = input;
     this.getLines().map(this.addLine.bind(this));
   }
 
@@ -17,9 +19,13 @@ export default abstract class Form {
   }
 
   private addLine(line: Line<any>) {
+    if (line.form !== undefined) {
+      throw new InconsistencyError('Line is already in a Form');
+    }
     try {
       this.getLine(line.id);
     } catch {
+      line.form = this;
       this._lines.push(line);
       return;
     }
@@ -33,4 +39,11 @@ export default abstract class Form {
     }
     return lines[0];
   }
+
+  getInput<T>(name: string): T {
+    if (!(name in this._input)) {
+      throw new NotFoundError(`No input with key ${name} on form ${this.name}`);
+    }
+    return this._input[name] as T;
+  }
 };
index e57888e5c759c79a68a5693f367b5541aede09d8..c0f76ef3b0ebaa18cf7694ae88b532a8a7661a17 100644 (file)
@@ -53,12 +53,22 @@ test('reference line', () => {
 });
 
 test('input line', () => {
-  const tr = new TaxReturn(2019, { 'key': 'value' });
+  class TestForm extends Form {
+    get name() { return 'F1'; }
 
-  const l1 = new InputLine<string>('1', 'key');
-  expect(l1.value(tr)).toBe('value');
+    protected getLines() {
+      return [
+        new InputLine<string>('1', 'key'),
+        new InputLine<string>('2', 'key2')
+      ];
+    }
+  };
+  const tr = new TaxReturn(2019);
+  const f = new TestForm({ 'key': 'value' });
 
-  const l2 = new InputLine<string>('2', 'key2');
+  expect(f.getLine('1').value(tr)).toBe('value');
+
+  const l2 = f.getLine('2');
   expect(() => l2.value(tr)).toThrow(NotFoundError);
 });
 
@@ -83,8 +93,8 @@ test('line stack', () => {
     }
   };
 
-  const tr = new TaxReturn(2019, { 'input': 100 });
-  tr.addForm(new FormZ());
+  const tr = new TaxReturn(2019);
+  tr.addForm(new FormZ({ 'input': 100 }));
   tr.addForm(new FormZ2());
 
   const l = new ReferenceLine<number>('32', 'Z-2', '2c');
index 92b601362d30c69f48ba167b7a15c6ee027a288b..0dd1b329a4d4c5d21e8ac3030a9c82825dd1c178 100644 (file)
@@ -1,9 +1,12 @@
 import TaxReturn from './TaxReturn';
+import Form from './Form';
 
 export abstract class Line<T> {
   private _id: string;
   private _description?: string;
 
+  form: Form;
+
   constructor(id: string, description?: string) {
     this._id = id;
     this._description = description;
@@ -59,6 +62,6 @@ export class InputLine<T> extends Line<T> {
   }
 
   value(tr: TaxReturn): T {
-    return tr.getInput<T>(this._input);
+    return this.form.getInput<T>(this._input);
   }
 };
index fa5b8cecdbafc35236bae0ecda702de3dcd4d9ee..74c82f427f74b60401947e3ddb11c5913dabd26f 100644 (file)
@@ -96,9 +96,3 @@ test('get non-existent form', () => {
   expect(() => tr.getForm('form')).toThrow(NotFoundError);
   expect(tr.getForms('form')).toEqual([]);
 });
-
-test('input', () => {
-  const tr = new TaxReturn(2019, { 'Filing Status': 'S' });
-  expect(tr.getInput('Filing Status')).toBe('S');
-  expect(() => tr.getInput('Unknown')).toThrow(NotFoundError);
-});
index 82e97fa46bc7be16986cf0f0c75df639067ef32a..18a0bbb031d9d3e5329bf03db8f4e299f9ab451a 100644 (file)
@@ -4,27 +4,18 @@ import { NotFoundError, InconsistencyError, UnsupportedFeatureError } from './Er
 
 export default class TaxReturn {
   private _year: number;
-  private _input: object;
 
   private _people: Person[] = [];
   private _forms: Form[] = [];
 
-  constructor(year: number, input?: object) {
+  constructor(year: number) {
     this._year = year;
-    this._input = input;
   }
 
   get year(): number {
     return this._year;
   }
 
-  getInput<T>(name: string): T {
-    if (!(name in this._input)) {
-      throw new NotFoundError(`No input with key ${name}`);
-    }
-    return this._input[name] as T;
-  }
-
   addPerson(person: Person) {
     if (person.relation == Relation.Dependent) {
       throw new UnsupportedFeatureError('Dependents are not supported');