us-tax-advantaged-params 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +2 -2
- package/dist/cjs/USTaxAdvantagedParams.js +43 -43
- package/dist/cjs/USTaxAdvantagedParams.js.map +1 -1
- package/dist/esm/USTaxAdvantagedParams.js +37 -37
- package/dist/esm/USTaxAdvantagedParams.js.map +1 -1
- package/dist/types/USTaxAdvantagedParams.d.cts +23 -23
- package/dist/types/USTaxAdvantagedParams.d.ts +23 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,30 @@ All notable changes to this project will be documented in this file. The project
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.0] - 2026-08-30
|
|
8
|
+
|
|
7
9
|
### Changed
|
|
8
10
|
|
|
11
|
+
- **Renamed the remaining retirement-scoped public symbols.** The package models only retirement accounts today, so these names were accurate, but they become wrong the moment a non-retirement account type lands, and renaming them after adoption would be a breaking change for real consumers. Done now, while the consumer count is zero:
|
|
12
|
+
|
|
13
|
+
| Before | After |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `RetirementAccountInput` | `AccountInput` |
|
|
16
|
+
| `RetirementScenarioInput` | `ScenarioInput` |
|
|
17
|
+
| `RetirementScenarioResult` | `ScenarioResult` |
|
|
18
|
+
| `RetirementAccountBuilder` | `AccountBuilder` |
|
|
19
|
+
| `RetirementScenario` | `Scenario` |
|
|
20
|
+
| `RetirementScenarioBuilder` | `ScenarioBuilder` |
|
|
21
|
+
| `RetirementParameterError` (TS) | `ParameterError` |
|
|
22
|
+
| `RetirementParameterException` (PHP) | `ParameterException` |
|
|
23
|
+
| `calculateRetirementScenario` (TS) | `calculateScenario` |
|
|
24
|
+
|
|
25
|
+
This makes the surface internally consistent: the prefix was already absent from `PersonBuilder`, `RothConversionBuilder`, `AccountType`, and `UnsupportedTaxYearError`/`Exception`, so the retirement-prefixed names were the minority, not the convention. `UnsupportedTaxYearError extends ParameterError` (and the PHP equivalent) is unchanged.
|
|
26
|
+
|
|
27
|
+
Genuinely retirement-specific *data* fields keep their names, because they describe retirement plans and will still be correct alongside other account types: `coveredByEmployerRetirementPlan` (the §219(g) active-participant test) and `selfEmployedRetirementDeduction`.
|
|
28
|
+
|
|
29
|
+
Breaking, with no compatibility aliases. Calculation behavior, the encoded 1975-2026 parameter range, the result shape, and the conformance vectors are unchanged — the 46-vector cross-language parity suite passes untouched.
|
|
30
|
+
|
|
9
31
|
- **Renamed the package and its public symbol.** The scope is broadening from federal retirement accounts to U.S. tax-advantaged accounts generally, so the identities were changed before the package acquired consumers:
|
|
10
32
|
- npm: `usa-retirement-account-parameters` → `us-tax-advantaged-params`
|
|
11
33
|
- Composer: `bherila/usa-retirement-account-parameters` → `bherila/us-tax-advantaged-params`
|
|
@@ -23,6 +45,8 @@ All notable changes to this project will be documented in this file. The project
|
|
|
23
45
|
|
|
24
46
|
## [0.1.0] - 2026-08-28
|
|
25
47
|
|
|
48
|
+
> **The `0.1.0` published to npm on 2026-08-30 does not match this entry.** It was built from a tree that already carried the package/symbol rename listed under 0.2.0 above, so its public API is `USTaxAdvantagedParams` with the `Retirement*`-prefixed member names — a combination no tagged release describes. It exists only because the rename was published before a release entry was cut. Use 0.2.0; `0.1.0` is superseded and should be treated as a bootstrap artifact.
|
|
49
|
+
|
|
26
50
|
### Fixed
|
|
27
51
|
|
|
28
52
|
- Designated Roth governmental 457(b) contributions are now gated on their statutory 2011 start date (Small Business Jobs Act of 2010, IRC §402A(e)(1)); earlier years return `unavailable` instead of a determinate Roth deferral.
|
package/README.md
CHANGED
|
@@ -141,7 +141,7 @@ require_once __DIR__ . '/vendor/autoload.php';
|
|
|
141
141
|
use USTaxAdvantagedParams\AccountType;
|
|
142
142
|
use USTaxAdvantagedParams\FilingStatus;
|
|
143
143
|
use USTaxAdvantagedParams\PersonBuilder;
|
|
144
|
-
use USTaxAdvantagedParams\
|
|
144
|
+
use USTaxAdvantagedParams\AccountBuilder;
|
|
145
145
|
use USTaxAdvantagedParams\USTaxAdvantagedParams as TaxAdvantagedParams;
|
|
146
146
|
|
|
147
147
|
$result = TaxAdvantagedParams::forTaxYear(2026)
|
|
@@ -168,7 +168,7 @@ $result = TaxAdvantagedParams::forTaxYear(2026)
|
|
|
168
168
|
'taxpayer-401k',
|
|
169
169
|
'taxpayer',
|
|
170
170
|
AccountType::TRADITIONAL_401K,
|
|
171
|
-
static function (
|
|
171
|
+
static function (AccountBuilder $account): void {
|
|
172
172
|
$account
|
|
173
173
|
->employer('employer-a')
|
|
174
174
|
->annualAdditionsGroup('employer-a')
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* determined defined-benefit/cash-balance contributions.
|
|
14
14
|
*/
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.USTaxAdvantagedParams = exports.
|
|
17
|
-
exports.
|
|
16
|
+
exports.USTaxAdvantagedParams = exports.ScenarioBuilder = exports.Scenario = exports.RothConversionBuilder = exports.AccountBuilder = exports.PersonBuilder = exports.UnsupportedTaxYearError = exports.ParameterError = exports.DiagnosticSeverity = exports.CalculationStatus = exports.ConversionType = exports.AccountType = exports.FilingStatus = exports.ENGINE_VERSION = exports.PACKAGE_NAME = void 0;
|
|
17
|
+
exports.calculateScenario = calculateScenario;
|
|
18
18
|
exports.PACKAGE_NAME = "us-tax-advantaged-params";
|
|
19
|
-
exports.ENGINE_VERSION = "0.
|
|
19
|
+
exports.ENGINE_VERSION = "0.2.0";
|
|
20
20
|
var FilingStatus;
|
|
21
21
|
(function (FilingStatus) {
|
|
22
22
|
FilingStatus["SINGLE"] = "single";
|
|
@@ -5325,16 +5325,16 @@ const RAW_PARAMETERS = {
|
|
|
5325
5325
|
}
|
|
5326
5326
|
};
|
|
5327
5327
|
/* </generated-parameters> */
|
|
5328
|
-
class
|
|
5328
|
+
class ParameterError extends Error {
|
|
5329
5329
|
code;
|
|
5330
5330
|
constructor(code, message) {
|
|
5331
5331
|
super(message);
|
|
5332
|
-
this.name = "
|
|
5332
|
+
this.name = "ParameterError";
|
|
5333
5333
|
this.code = code;
|
|
5334
5334
|
}
|
|
5335
5335
|
}
|
|
5336
|
-
exports.
|
|
5337
|
-
class UnsupportedTaxYearError extends
|
|
5336
|
+
exports.ParameterError = ParameterError;
|
|
5337
|
+
class UnsupportedTaxYearError extends ParameterError {
|
|
5338
5338
|
constructor(year, minimum, maximum) {
|
|
5339
5339
|
super("UNSUPPORTED_TAX_YEAR", `Tax year ${year} is not supported. Supported years are ${minimum}-${maximum}; future years are never extrapolated.`);
|
|
5340
5340
|
this.name = "UnsupportedTaxYearError";
|
|
@@ -5597,7 +5597,7 @@ function parseFilingStatus(value, diagnostics) {
|
|
|
5597
5597
|
const token = normalizeToken(String(value));
|
|
5598
5598
|
const parsed = FILING_STATUS_ALIASES[token];
|
|
5599
5599
|
if (!parsed) {
|
|
5600
|
-
throw new
|
|
5600
|
+
throw new ParameterError("INVALID_FILING_STATUS", `Unsupported filing status: ${value}`);
|
|
5601
5601
|
}
|
|
5602
5602
|
if (token === "M") {
|
|
5603
5603
|
diagnostics?.push(diagnostic("AMBIGUOUS_M_ALIAS_ASSUMED_MFJ", DiagnosticSeverity.WARNING, 'Filing-status alias "M" was interpreted as married filing jointly. Use MFJ or MFS to be explicit.', "filingStatus"));
|
|
@@ -5610,7 +5610,7 @@ function parseAccountType(value) {
|
|
|
5610
5610
|
}
|
|
5611
5611
|
const parsed = ACCOUNT_TYPE_ALIASES[normalizeToken(String(value))];
|
|
5612
5612
|
if (!parsed) {
|
|
5613
|
-
throw new
|
|
5613
|
+
throw new ParameterError("INVALID_ACCOUNT_TYPE", `Unsupported retirement account type: ${value}`);
|
|
5614
5614
|
}
|
|
5615
5615
|
return parsed;
|
|
5616
5616
|
}
|
|
@@ -5620,7 +5620,7 @@ function parseConversionType(value) {
|
|
|
5620
5620
|
}
|
|
5621
5621
|
const parsed = CONVERSION_TYPE_ALIASES[normalizeToken(String(value))];
|
|
5622
5622
|
if (!parsed) {
|
|
5623
|
-
throw new
|
|
5623
|
+
throw new ParameterError("INVALID_CONVERSION_TYPE", `Unsupported Roth conversion type: ${value}`);
|
|
5624
5624
|
}
|
|
5625
5625
|
return parsed;
|
|
5626
5626
|
}
|
|
@@ -5631,7 +5631,7 @@ function money(value, path, defaultValue = 0) {
|
|
|
5631
5631
|
if (value === undefined || value === null)
|
|
5632
5632
|
return defaultValue;
|
|
5633
5633
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
5634
|
-
throw new
|
|
5634
|
+
throw new ParameterError("INVALID_MONEY", `${path} must be a finite, nonnegative number.`);
|
|
5635
5635
|
}
|
|
5636
5636
|
return roundMoney(value);
|
|
5637
5637
|
}
|
|
@@ -5639,7 +5639,7 @@ function rate(value, path, defaultValue = 0) {
|
|
|
5639
5639
|
if (value === undefined || value === null)
|
|
5640
5640
|
return defaultValue;
|
|
5641
5641
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
5642
|
-
throw new
|
|
5642
|
+
throw new ParameterError("INVALID_RATE", `${path} must be a number from 0 through 1.`);
|
|
5643
5643
|
}
|
|
5644
5644
|
return value;
|
|
5645
5645
|
}
|
|
@@ -5781,7 +5781,7 @@ function mergeTaxEffects(target, source) {
|
|
|
5781
5781
|
}
|
|
5782
5782
|
function getParametersForYear(year) {
|
|
5783
5783
|
if (!Number.isInteger(year)) {
|
|
5784
|
-
throw new
|
|
5784
|
+
throw new ParameterError("INVALID_TAX_YEAR", "taxYear must be an integer.");
|
|
5785
5785
|
}
|
|
5786
5786
|
const { minimum, maximum } = RAW_PARAMETERS.supportedTaxYears;
|
|
5787
5787
|
if (year < minimum || year > maximum || !RAW_PARAMETERS.years[String(year)]) {
|
|
@@ -5794,18 +5794,18 @@ function deepClone(value) {
|
|
|
5794
5794
|
}
|
|
5795
5795
|
function normalizePersons(persons) {
|
|
5796
5796
|
if (!Array.isArray(persons) || persons.length === 0) {
|
|
5797
|
-
throw new
|
|
5797
|
+
throw new ParameterError("PERSON_REQUIRED", "At least one person is required.");
|
|
5798
5798
|
}
|
|
5799
5799
|
const result = new Map();
|
|
5800
5800
|
for (const [index, input] of persons.entries()) {
|
|
5801
5801
|
if (!input.id?.trim()) {
|
|
5802
|
-
throw new
|
|
5802
|
+
throw new ParameterError("PERSON_ID_REQUIRED", `persons[${index}].id is required.`);
|
|
5803
5803
|
}
|
|
5804
5804
|
if (result.has(input.id)) {
|
|
5805
|
-
throw new
|
|
5805
|
+
throw new ParameterError("DUPLICATE_PERSON_ID", `Duplicate person ID: ${input.id}`);
|
|
5806
5806
|
}
|
|
5807
5807
|
if (input.birthYear !== undefined && (!Number.isInteger(input.birthYear) || input.birthYear < 1800 || input.birthYear > 3000)) {
|
|
5808
|
-
throw new
|
|
5808
|
+
throw new ParameterError("INVALID_BIRTH_YEAR", `persons[${index}].birthYear is invalid.`);
|
|
5809
5809
|
}
|
|
5810
5810
|
if (input.birthDate !== undefined)
|
|
5811
5811
|
validateIsoDate(input.birthDate, `persons[${index}].birthDate`);
|
|
@@ -5823,7 +5823,7 @@ function normalizePersons(persons) {
|
|
|
5823
5823
|
}
|
|
5824
5824
|
const role = input.role ?? (index === 0 ? "taxpayer" : index === 1 ? "spouse" : "other");
|
|
5825
5825
|
if (role !== "taxpayer" && role !== "spouse" && role !== "other") {
|
|
5826
|
-
throw new
|
|
5826
|
+
throw new ParameterError("INVALID_PERSON_ROLE", `persons[${index}].role must be taxpayer, spouse, or other.`);
|
|
5827
5827
|
}
|
|
5828
5828
|
result.set(input.id, {
|
|
5829
5829
|
...input,
|
|
@@ -5845,7 +5845,7 @@ function normalizePersons(persons) {
|
|
|
5845
5845
|
for (const role of ["taxpayer", "spouse"]) {
|
|
5846
5846
|
const matching = [...result.values()].filter((person) => person.role === role);
|
|
5847
5847
|
if (matching.length > 1) {
|
|
5848
|
-
throw new
|
|
5848
|
+
throw new ParameterError("DUPLICATE_PERSON_ROLE", `Only one person may have the ${role} role; found ${matching.map((person) => person.id).join(", ")}.`);
|
|
5849
5849
|
}
|
|
5850
5850
|
}
|
|
5851
5851
|
return result;
|
|
@@ -5854,14 +5854,14 @@ function normalizeAccounts(accounts, persons) {
|
|
|
5854
5854
|
const ids = new Set();
|
|
5855
5855
|
return accounts.map((input, index) => {
|
|
5856
5856
|
if (!input.id?.trim()) {
|
|
5857
|
-
throw new
|
|
5857
|
+
throw new ParameterError("ACCOUNT_ID_REQUIRED", `accounts[${index}].id is required.`);
|
|
5858
5858
|
}
|
|
5859
5859
|
if (ids.has(input.id)) {
|
|
5860
|
-
throw new
|
|
5860
|
+
throw new ParameterError("DUPLICATE_ACCOUNT_ID", `Duplicate account ID: ${input.id}`);
|
|
5861
5861
|
}
|
|
5862
5862
|
ids.add(input.id);
|
|
5863
5863
|
if (!persons.has(input.ownerId)) {
|
|
5864
|
-
throw new
|
|
5864
|
+
throw new ParameterError("UNKNOWN_ACCOUNT_OWNER", `Account ${input.id} references unknown owner ${input.ownerId}.`);
|
|
5865
5865
|
}
|
|
5866
5866
|
const planRules = input.planRules ?? {};
|
|
5867
5867
|
validatePlanRules(planRules, `accounts[${index}].planRules`);
|
|
@@ -5890,7 +5890,7 @@ function validatePlanRules(rules, path) {
|
|
|
5890
5890
|
if (rules.special403bCatchUp) {
|
|
5891
5891
|
const special = rules.special403bCatchUp;
|
|
5892
5892
|
if (!Number.isFinite(special.yearsOfService) || special.yearsOfService < 0) {
|
|
5893
|
-
throw new
|
|
5893
|
+
throw new ParameterError("INVALID_YEARS_OF_SERVICE", `${path}.special403bCatchUp.yearsOfService is invalid.`);
|
|
5894
5894
|
}
|
|
5895
5895
|
money(special.priorElectiveDeferrals, `${path}.special403bCatchUp.priorElectiveDeferrals`);
|
|
5896
5896
|
money(special.priorSpecialCatchUpUsed, `${path}.special403bCatchUp.priorSpecialCatchUpUsed`);
|
|
@@ -5901,12 +5901,12 @@ function validatePlanRules(rules, path) {
|
|
|
5901
5901
|
}
|
|
5902
5902
|
function validateIsoDate(value, path) {
|
|
5903
5903
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
5904
|
-
throw new
|
|
5904
|
+
throw new ParameterError("INVALID_DATE", `${path} must use YYYY-MM-DD.`);
|
|
5905
5905
|
}
|
|
5906
5906
|
const [year, month, day] = value.split("-").map(Number);
|
|
5907
5907
|
const date = new Date(Date.UTC(year, month - 1, day));
|
|
5908
5908
|
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) {
|
|
5909
|
-
throw new
|
|
5909
|
+
throw new ParameterError("INVALID_DATE", `${path} is not a valid calendar date.`);
|
|
5910
5910
|
}
|
|
5911
5911
|
}
|
|
5912
5912
|
function ageAtEndOfTaxYear(person, taxYear) {
|
|
@@ -7244,17 +7244,17 @@ function normalizeConversions(conversions, persons, accountsById) {
|
|
|
7244
7244
|
const ids = new Set();
|
|
7245
7245
|
return conversions.map((input, index) => {
|
|
7246
7246
|
if (!input.id?.trim()) {
|
|
7247
|
-
throw new
|
|
7247
|
+
throw new ParameterError("CONVERSION_ID_REQUIRED", `conversions[${index}].id is required.`);
|
|
7248
7248
|
}
|
|
7249
7249
|
if (ids.has(input.id)) {
|
|
7250
|
-
throw new
|
|
7250
|
+
throw new ParameterError("DUPLICATE_CONVERSION_ID", `Duplicate conversion ID: ${input.id}`);
|
|
7251
7251
|
}
|
|
7252
7252
|
ids.add(input.id);
|
|
7253
7253
|
if (!persons.has(input.ownerId)) {
|
|
7254
|
-
throw new
|
|
7254
|
+
throw new ParameterError("UNKNOWN_CONVERSION_OWNER", `Conversion ${input.id} references unknown owner ${input.ownerId}.`);
|
|
7255
7255
|
}
|
|
7256
7256
|
if (input.sourceAccountId && !accountsById.has(input.sourceAccountId)) {
|
|
7257
|
-
throw new
|
|
7257
|
+
throw new ParameterError("UNKNOWN_CONVERSION_SOURCE_ACCOUNT", `Conversion ${input.id} references unknown source account ${input.sourceAccountId}.`);
|
|
7258
7258
|
}
|
|
7259
7259
|
return {
|
|
7260
7260
|
...input,
|
|
@@ -7471,7 +7471,7 @@ function calculateIraConversionGroup(context, ownerId, conversions, accountResul
|
|
|
7471
7471
|
};
|
|
7472
7472
|
});
|
|
7473
7473
|
}
|
|
7474
|
-
function
|
|
7474
|
+
function calculateScenario(input) {
|
|
7475
7475
|
const scenarioDiagnostics = [];
|
|
7476
7476
|
const taxYear = input.taxYear;
|
|
7477
7477
|
const parameters = getParametersForYear(taxYear);
|
|
@@ -7669,7 +7669,7 @@ class PersonBuilder {
|
|
|
7669
7669
|
}
|
|
7670
7670
|
}
|
|
7671
7671
|
exports.PersonBuilder = PersonBuilder;
|
|
7672
|
-
class
|
|
7672
|
+
class AccountBuilder {
|
|
7673
7673
|
value;
|
|
7674
7674
|
constructor(id, ownerId, type) {
|
|
7675
7675
|
this.value = {
|
|
@@ -7794,7 +7794,7 @@ class RetirementAccountBuilder {
|
|
|
7794
7794
|
return deepClone(this.value);
|
|
7795
7795
|
}
|
|
7796
7796
|
}
|
|
7797
|
-
exports.
|
|
7797
|
+
exports.AccountBuilder = AccountBuilder;
|
|
7798
7798
|
class RothConversionBuilder {
|
|
7799
7799
|
value;
|
|
7800
7800
|
constructor(id, ownerId, type, amount) {
|
|
@@ -7825,23 +7825,23 @@ class RothConversionBuilder {
|
|
|
7825
7825
|
}
|
|
7826
7826
|
}
|
|
7827
7827
|
exports.RothConversionBuilder = RothConversionBuilder;
|
|
7828
|
-
class
|
|
7828
|
+
class Scenario {
|
|
7829
7829
|
input;
|
|
7830
7830
|
constructor(input) {
|
|
7831
7831
|
this.input = input;
|
|
7832
7832
|
}
|
|
7833
7833
|
calculate() {
|
|
7834
|
-
return
|
|
7834
|
+
return calculateScenario(deepClone(this.input));
|
|
7835
7835
|
}
|
|
7836
7836
|
toInput() {
|
|
7837
7837
|
return deepClone(this.input);
|
|
7838
7838
|
}
|
|
7839
7839
|
}
|
|
7840
|
-
exports.
|
|
7841
|
-
class
|
|
7840
|
+
exports.Scenario = Scenario;
|
|
7841
|
+
class ScenarioBuilder {
|
|
7842
7842
|
value;
|
|
7843
7843
|
static forTaxYear(taxYear) {
|
|
7844
|
-
return new
|
|
7844
|
+
return new ScenarioBuilder(taxYear);
|
|
7845
7845
|
}
|
|
7846
7846
|
constructor(taxYear) {
|
|
7847
7847
|
this.value = {
|
|
@@ -7871,11 +7871,11 @@ class RetirementScenarioBuilder {
|
|
|
7871
7871
|
return this.addPerson(builder);
|
|
7872
7872
|
}
|
|
7873
7873
|
addAccount(account) {
|
|
7874
|
-
this.value.accounts.push(account instanceof
|
|
7874
|
+
this.value.accounts.push(account instanceof AccountBuilder ? account.build() : deepClone(account));
|
|
7875
7875
|
return this;
|
|
7876
7876
|
}
|
|
7877
7877
|
account(id, ownerId, type, configure) {
|
|
7878
|
-
const builder = new
|
|
7878
|
+
const builder = new AccountBuilder(id, ownerId, type);
|
|
7879
7879
|
configure?.(builder);
|
|
7880
7880
|
return this.addAccount(builder);
|
|
7881
7881
|
}
|
|
@@ -7889,7 +7889,7 @@ class RetirementScenarioBuilder {
|
|
|
7889
7889
|
return this.addConversion(builder);
|
|
7890
7890
|
}
|
|
7891
7891
|
build() {
|
|
7892
|
-
return new
|
|
7892
|
+
return new Scenario(deepClone(this.value));
|
|
7893
7893
|
}
|
|
7894
7894
|
calculate() {
|
|
7895
7895
|
return this.build().calculate();
|
|
@@ -7898,13 +7898,13 @@ class RetirementScenarioBuilder {
|
|
|
7898
7898
|
return deepClone(this.value);
|
|
7899
7899
|
}
|
|
7900
7900
|
}
|
|
7901
|
-
exports.
|
|
7901
|
+
exports.ScenarioBuilder = ScenarioBuilder;
|
|
7902
7902
|
class USTaxAdvantagedParams {
|
|
7903
7903
|
static forTaxYear(taxYear) {
|
|
7904
|
-
return
|
|
7904
|
+
return ScenarioBuilder.forTaxYear(taxYear);
|
|
7905
7905
|
}
|
|
7906
7906
|
static calculate(input) {
|
|
7907
|
-
return
|
|
7907
|
+
return calculateScenario(input);
|
|
7908
7908
|
}
|
|
7909
7909
|
static parametersForYear(taxYear) {
|
|
7910
7910
|
return getParametersForYear(taxYear);
|