Select Git revision
VariableReferredParameters.svelte
-
Dorine Lambinet authoredDorine Lambinet authored
variables.ts 6.43 KiB
import variableSummaryByNameUnknown from "@openfisca/france-json/variables_summaries.json"
import type {
Formula,
Reference,
Variable,
VariableByName,
} from "@openfisca/json-model"
import type { CalculationName } from "$lib/calculations"
import { reformChangesByName } from "$lib/reforms"
export interface InstantFormulaAndReferences {
formula?: Formula
instant: string
references: Reference[]
}
export type ValuesByCalculationNameByVariableName = {
[variableName: string]: VariableValuesByCalculationName
}
export type VariableValueByCalculationName = Partial<{
[calculationName in CalculationName]: VariableValue
}>
export type VariableValuesByCalculationName = Partial<{
[calculationName in CalculationName]: VariableValues
}>
export type VariableValue = boolean | number | string
export type VariableValues = boolean[] | number[] | string[]
/// Name of variables that must be calculated to be displayed in
/// test case summaries.
export const summaryCalculatedVariablesName = [
"assiette_csg_revenus_capital",
"assiette_csg_plus_values",
"plus_values_base_large",
"rente_viagere_titre_onereux_net",
"rsa",
]
export const variableSummaryByName =
variableSummaryByNameUnknown as VariableByName
export const variableSummaryByNameByReformName: {
[name: string]: VariableByName
} = Object.fromEntries(
Object.entries(reformChangesByName).map(([reformName, reformChanges]) => [
reformName,
patchVariableSummaryByName(
variableSummaryByName,
reformChanges.variables_summaries,
),
]),
)
export function buildInstantFormulaAndReferencesArray(
variable: Variable,
): InstantFormulaAndReferences[] {
const instantFormulaAndReferencesByInstant: {
[instant: string]: InstantFormulaAndReferences
} = Object.fromEntries(
Object.entries(variable.formulas ?? {}).map(([instant, formula]) => [
instant,
{ formula, instant, references: [] },
]),
)
if (variable.reference !== undefined) {
for (const [instant, references] of Object.entries(variable.reference)) {
if (instantFormulaAndReferencesByInstant[instant] === undefined) {
instantFormulaAndReferencesByInstant[instant] = {
instant,
references,
}
} else {
instantFormulaAndReferencesByInstant[instant].references = references
}
}
}
return Object.entries(instantFormulaAndReferencesByInstant)
.sort(([instant1], [instant2]) => instant2.localeCompare(instant1))
.map(([, instantFormulaAndReferences]) => instantFormulaAndReferences)
}
export function getVariableParametersName(
variable: Variable,
date: string,
): string[] | undefined {
if (variable.input || variable.formulas === undefined) {
// Variable is an input variable => No parameter.
return undefined
}
const dates = Object.keys(variable.formulas).reverse()
let formula: Formula | undefined = undefined
for (const bestDate of dates) {
if (bestDate <= date) {
formula = variable.formulas[bestDate]
break
}
}
if (formula == null) {
// No candidate date less than or equal to date found.
return undefined
}
return formula.parameters
}
export function* iterVariableInputVariables(
variable: Variable,
date: string,
encounteredVariablesName: Set<string> = new Set(),
): Generator<Variable, void> {
const name = variable.name
if (encounteredVariablesName.has(name)) {
return
}
encounteredVariablesName.add(name)
if (variable.input) {
// Variable has been customized to an input variable.
yield variable
return
}
const formulas = variable.formulas
if (formulas === undefined) {
// Variable is an input variable.
yield variable
return
}
const dates = Object.keys(formulas).reverse()
let formula = undefined
for (const bestDate of dates) {
if (bestDate <= date) {
formula = formulas[bestDate]
break
}
}
if (formula == null) {
// No candidate date less than or equal to date found.
return
}
const referredVariablesName = formula.variables
if (referredVariablesName === undefined) {
return
}
for (const referredVariableName of referredVariablesName) {
const referredVariable = variableSummaryByName[referredVariableName]
yield* iterVariableInputVariables(
referredVariable,
date,
encounteredVariablesName,
)
}
}
export function* iterVariableParametersName(
variable: Variable,
date: string,
encounteredParametersName: Set<string> = new Set(),
encounteredVariablesName: Set<string> = new Set(),
): Generator<string, void> {
const name = variable.name
if (encounteredVariablesName.has(name)) {
return
}
encounteredVariablesName.add(name)
const formulas = variable.formulas
if (formulas === undefined) {
return
}
const dates = Object.keys(formulas).reverse()
let formula = undefined
for (const bestDate of dates) {
if (bestDate <= date) {
formula = formulas[bestDate]
break
}
}
if (formula == null) {
// No candidate date less than or equal to date found.
return
}
const referredVariablesName = formula.variables
if (referredVariablesName !== undefined) {
for (const referredVariableName of referredVariablesName) {
const referredVariable = variableSummaryByName[referredVariableName]
yield* iterVariableParametersName(
referredVariable,
date,
encounteredParametersName,
encounteredVariablesName,
)
}
}
const referredParametersName = formula.parameters
if (referredParametersName !== undefined) {
for (const referredParameterName of referredParametersName) {
if (encounteredParametersName.has(referredParameterName)) {
continue
}
encounteredParametersName.add(referredParameterName)
yield referredParameterName
}
}
}
function patchVariableSummaryByName(
variableSummaryByName: VariableByName,
patch: { [name: string]: Variable | null },
): VariableByName {
if (Object.keys(patch).length === 0) {
return variableSummaryByName
}
const patchedVariableSummaryByName = { ...variableSummaryByName }
for (const [name, variableSummaryPatch] of Object.entries(patch)) {
if (variableSummaryPatch === null) {
// This case should not occur, because a reform should always
// have all the variables of the original tax-benefit system.
delete patchedVariableSummaryByName[name]
} else {
patchedVariableSummaryByName[name] = variableSummaryPatch
}
}
return patchedVariableSummaryByName
}