2020-04-20 21:35:03 +00:00
|
|
|
/**
|
|
|
|
* Note: all here is strictly based on duck typing.
|
|
|
|
* We don't exepect the parent rule to explain the type of the contained formula, for example.
|
|
|
|
*/
|
|
|
|
|
2020-04-21 20:56:40 +00:00
|
|
|
import R from 'ramda'
|
2020-04-24 18:32:24 +00:00
|
|
|
import { ArrondiExplanation } from './mecanisms/arrondi'
|
2020-04-21 12:23:58 +00:00
|
|
|
import { ParsedRule, ParsedRules } from './types'
|
2020-04-20 21:35:03 +00:00
|
|
|
|
2020-04-23 16:39:56 +00:00
|
|
|
type OnOff = 'oui' | 'non'
|
|
|
|
export function isOnOff(a: string): a is OnOff {
|
|
|
|
return a === 'oui' || a === 'non'
|
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
// Note: to build type-guards, we would need to have a `isNames` guard. That's
|
|
|
|
// pretty cumbersome, so for now we rely on this.
|
2020-04-23 16:39:56 +00:00
|
|
|
type WannabeDottedName = string
|
|
|
|
export function isWannabeDottedName(a: string): a is WannabeDottedName {
|
|
|
|
return typeof a === 'string'
|
|
|
|
}
|
2020-04-20 21:35:03 +00:00
|
|
|
|
2020-04-23 16:39:56 +00:00
|
|
|
type ASTNode = { [_: string]: {} | undefined }
|
2020-04-20 21:35:03 +00:00
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type RuleNode<Names extends string> = ASTNode & ParsedRule<Names>
|
2020-04-24 19:32:05 +00:00
|
|
|
|
|
|
|
type RuleProp = ASTNode & {
|
|
|
|
category: 'ruleProp'
|
|
|
|
rulePropType: string
|
|
|
|
}
|
|
|
|
export function isRuleProp(node: ASTNode): node is RuleProp {
|
|
|
|
return (
|
|
|
|
(node as RuleProp).category === 'ruleProp' &&
|
|
|
|
typeof (node as RuleProp).rulePropType === 'string'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type CondRuleProp = RuleProp & {
|
|
|
|
rulePropType: 'cond'
|
|
|
|
}
|
|
|
|
export function isCondRuleProp(node: ASTNode): node is CondRuleProp {
|
|
|
|
return isRuleProp(node) && (node as CondRuleProp).rulePropType === 'cond'
|
|
|
|
}
|
|
|
|
|
2020-04-24 19:45:25 +00:00
|
|
|
// [XXX] - What about 'rend non applicable'? Unclear what to do in this case, it seems it would create a graph edge in the contrary sense?
|
2020-04-24 19:32:05 +00:00
|
|
|
type ApplicableSi = CondRuleProp & {
|
|
|
|
dottedName: 'applicable si'
|
|
|
|
explanation: ASTNode
|
|
|
|
}
|
|
|
|
export function isApplicableSi(node: ASTNode): node is ApplicableSi {
|
|
|
|
const applicableSi = node as ApplicableSi
|
|
|
|
return (
|
|
|
|
isCondRuleProp(node) &&
|
|
|
|
applicableSi.dottedName === 'applicable si' &&
|
|
|
|
applicableSi.explanation !== undefined
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type NonApplicableSi = CondRuleProp & {
|
|
|
|
dottedName: 'non applicable si'
|
|
|
|
explanation: ASTNode
|
|
|
|
}
|
|
|
|
export function isNonApplicableSi(node: ASTNode): node is NonApplicableSi {
|
|
|
|
const nonApplicableSi = node as NonApplicableSi
|
|
|
|
return (
|
|
|
|
isCondRuleProp(node) &&
|
|
|
|
nonApplicableSi.dottedName === 'non applicable si' &&
|
|
|
|
nonApplicableSi.explanation !== undefined
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type Formule<Names extends string> = RuleProp & {
|
2020-04-24 19:32:05 +00:00
|
|
|
name: 'formule'
|
|
|
|
rulePropType: 'formula'
|
2020-05-06 15:26:45 +00:00
|
|
|
explanation: FormuleExplanation<Names>
|
2020-04-24 19:32:05 +00:00
|
|
|
}
|
2020-05-06 15:26:45 +00:00
|
|
|
export function isFormule<Names extends string>(
|
2020-04-24 19:32:05 +00:00
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
): node is Formule<Names> {
|
|
|
|
const formule = node as Formule<Names>
|
2020-04-24 19:32:05 +00:00
|
|
|
return (
|
|
|
|
isRuleProp(node) &&
|
|
|
|
formule.name === 'formule' &&
|
|
|
|
formule.rulePropType === 'formula' &&
|
2020-05-06 15:26:45 +00:00
|
|
|
isFormuleExplanation<Names>(formule.explanation)
|
2020-04-24 19:32:05 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type FormuleExplanation<Names extends string> =
|
2020-04-24 19:32:05 +00:00
|
|
|
| Value
|
|
|
|
| Operation
|
|
|
|
| Possibilities
|
|
|
|
| Possibilities2
|
2020-05-06 15:26:45 +00:00
|
|
|
| Reference<Names>
|
|
|
|
| AnyMechanism<Names>
|
|
|
|
export function isFormuleExplanation<Names extends string>(
|
2020-04-24 19:32:05 +00:00
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
): node is FormuleExplanation<Names> {
|
2020-04-24 19:32:05 +00:00
|
|
|
return (
|
|
|
|
isValue(node) ||
|
|
|
|
isOperation(node) ||
|
|
|
|
isReference(node) ||
|
|
|
|
isPossibilities(node) ||
|
|
|
|
isPossibilities2(node) ||
|
2020-05-06 15:26:45 +00:00
|
|
|
isAnyMechanism<Names>(node)
|
2020-04-24 19:32:05 +00:00
|
|
|
)
|
|
|
|
}
|
2020-04-20 21:35:03 +00:00
|
|
|
|
2020-04-21 12:23:58 +00:00
|
|
|
type Value = ASTNode & {
|
2020-04-24 18:32:24 +00:00
|
|
|
nodeValue: number | string | boolean
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
2020-04-21 20:56:40 +00:00
|
|
|
export function isValue(node: ASTNode): node is Value {
|
2020-04-23 16:39:56 +00:00
|
|
|
const value = node as Value
|
2020-04-21 12:23:58 +00:00
|
|
|
return (
|
2020-04-24 18:32:24 +00:00
|
|
|
typeof value.nodeValue === 'string' ||
|
|
|
|
typeof value.nodeValue === 'number' ||
|
|
|
|
typeof value.nodeValue === 'boolean'
|
2020-04-21 12:23:58 +00:00
|
|
|
)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 12:23:58 +00:00
|
|
|
type Operation = ASTNode & {
|
|
|
|
operationType: 'comparison' | 'calculation'
|
2020-04-21 20:56:40 +00:00
|
|
|
explanation: Array<ASTNode>
|
2020-04-21 12:23:58 +00:00
|
|
|
}
|
2020-04-21 20:56:40 +00:00
|
|
|
export function isOperation(node: ASTNode): node is Operation {
|
2020-04-23 16:39:56 +00:00
|
|
|
return R.includes((node as Operation).operationType, [
|
|
|
|
'comparison',
|
|
|
|
'calculation'
|
|
|
|
])
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 12:23:58 +00:00
|
|
|
type Possibilities = ASTNode & {
|
|
|
|
possibilités: Array<string>
|
2020-04-23 16:39:56 +00:00
|
|
|
'choix obligatoire'?: OnOff
|
|
|
|
'une possibilité': OnOff
|
2020-04-21 12:23:58 +00:00
|
|
|
}
|
2020-04-21 20:56:40 +00:00
|
|
|
export function isPossibilities(node: ASTNode): node is Possibilities {
|
2020-04-21 12:23:58 +00:00
|
|
|
const possibilities = node as Possibilities
|
|
|
|
return (
|
|
|
|
possibilities.possibilités instanceof Array &&
|
|
|
|
possibilities.possibilités.every(it => typeof it === 'string') &&
|
2020-04-21 20:56:40 +00:00
|
|
|
(possibilities['choix obligatoire'] === undefined ||
|
2020-04-23 16:39:56 +00:00
|
|
|
isOnOff(possibilities['choix obligatoire'])) &&
|
|
|
|
isOnOff(possibilities['une possibilité'])
|
2020-04-21 12:23:58 +00:00
|
|
|
)
|
|
|
|
}
|
2020-04-24 18:32:24 +00:00
|
|
|
type Possibilities2 = ASTNode & {
|
|
|
|
[index: number]: string // short dotted name
|
|
|
|
'choix obligatoire'?: OnOff
|
|
|
|
'une possibilité': OnOff
|
|
|
|
}
|
|
|
|
export function isPossibilities2(node: ASTNode): node is Possibilities2 {
|
|
|
|
const possibilities2 = node as Possibilities2
|
|
|
|
return (
|
2020-05-06 15:10:10 +00:00
|
|
|
Object.entries(possibilities2).every(
|
|
|
|
([k, v]) => isNaN(parseInt(k, 10)) || typeof v === 'string'
|
2020-04-24 18:32:24 +00:00
|
|
|
) &&
|
|
|
|
(possibilities2['choix obligatoire'] === undefined ||
|
|
|
|
isOnOff(possibilities2['choix obligatoire'])) &&
|
|
|
|
isOnOff(possibilities2['une possibilité'])
|
|
|
|
)
|
|
|
|
}
|
2020-04-21 12:23:58 +00:00
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type Reference<Names extends string> = ASTNode & {
|
2020-04-21 12:23:58 +00:00
|
|
|
category: 'reference'
|
2020-05-06 15:26:45 +00:00
|
|
|
name: Names
|
|
|
|
partialReference: Names
|
|
|
|
dottedName: Names
|
2020-04-21 12:23:58 +00:00
|
|
|
}
|
2020-05-06 15:26:45 +00:00
|
|
|
export function isReference<Names extends string>(
|
2020-04-21 20:56:40 +00:00
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
): node is Reference<Names> {
|
|
|
|
const reference = node as Reference<Names>
|
2020-04-21 20:56:40 +00:00
|
|
|
return (
|
2020-04-23 16:39:56 +00:00
|
|
|
reference.category === 'reference' &&
|
|
|
|
isWannabeDottedName(reference.name) &&
|
|
|
|
isWannabeDottedName(reference.partialReference) &&
|
|
|
|
isWannabeDottedName(reference.dottedName)
|
2020-04-21 20:56:40 +00:00
|
|
|
)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-24 19:32:05 +00:00
|
|
|
type AbstractMechanism = ASTNode & {
|
|
|
|
category: 'mecanism'
|
|
|
|
name: string
|
|
|
|
}
|
|
|
|
export function isAbstractMechanism(node: ASTNode): node is AbstractMechanism {
|
|
|
|
return (
|
|
|
|
(node as AbstractMechanism).category === 'mecanism' &&
|
|
|
|
typeof (node as AbstractMechanism).name === 'string'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type RecalculMech<Names extends string> = AbstractMechanism & {
|
2020-04-21 12:23:58 +00:00
|
|
|
explanation: {
|
2020-05-06 15:26:45 +00:00
|
|
|
recalcul: Reference<Names>
|
|
|
|
amendedSituation: Record<Names, Reference<Names>>
|
2020-04-21 12:23:58 +00:00
|
|
|
}
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
2020-05-06 15:26:45 +00:00
|
|
|
export function isRecalculMech<Names extends string>(
|
2020-04-21 20:56:40 +00:00
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
): node is RecalculMech<Names> {
|
|
|
|
const recalculMech = node as RecalculMech<Names>
|
2020-04-24 18:32:24 +00:00
|
|
|
const isReferenceSpec = isReference as (
|
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
) => node is Reference<Names>
|
2020-04-21 12:23:58 +00:00
|
|
|
return (
|
2020-04-24 19:32:05 +00:00
|
|
|
typeof recalculMech.explanation === 'object' &&
|
|
|
|
typeof recalculMech.explanation.recalcul === 'object' &&
|
|
|
|
isReferenceSpec(recalculMech.explanation.recalcul as ASTNode) &&
|
|
|
|
typeof recalculMech.explanation.amendedSituation === 'object'
|
2020-04-21 12:23:58 +00:00
|
|
|
)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 16:39:56 +00:00
|
|
|
type EncadrementMech = AbstractMechanism & {
|
|
|
|
name: 'encadrement'
|
2020-04-24 18:32:24 +00:00
|
|
|
explanation: {
|
|
|
|
valeur: ASTNode
|
|
|
|
plafond: ASTNode
|
|
|
|
plancher: ASTNode
|
2020-04-23 16:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isEncadrementMech(node: ASTNode): node is EncadrementMech {
|
|
|
|
const encadrementMech = node as EncadrementMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(encadrementMech) &&
|
2020-04-24 18:32:24 +00:00
|
|
|
encadrementMech.name == 'encadrement' &&
|
|
|
|
typeof encadrementMech.explanation === 'object' &&
|
|
|
|
encadrementMech.explanation.valeur !== undefined &&
|
|
|
|
encadrementMech.explanation.plafond !== undefined &&
|
|
|
|
encadrementMech.explanation.plancher !== undefined
|
2020-04-23 16:39:56 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type SommeMech = AbstractMechanism & {
|
|
|
|
name: 'somme'
|
|
|
|
explanation: Array<ASTNode>
|
|
|
|
}
|
|
|
|
export function isSommeMech(node: ASTNode): node is SommeMech {
|
|
|
|
const sommeMech = node as SommeMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(sommeMech) &&
|
|
|
|
sommeMech.name === 'somme' &&
|
2020-04-24 18:32:24 +00:00
|
|
|
sommeMech.explanation instanceof Array
|
2020-04-23 16:39:56 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ProduitMech = AbstractMechanism & {
|
|
|
|
name: 'produit'
|
|
|
|
explanation: {
|
|
|
|
assiette: ASTNode
|
|
|
|
plafond: ASTNode
|
|
|
|
facteur: ASTNode
|
|
|
|
taux: ASTNode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isProduitMech(node: ASTNode): node is ProduitMech {
|
|
|
|
const produitMech = node as ProduitMech
|
|
|
|
return (
|
2020-04-24 18:32:24 +00:00
|
|
|
isAbstractMechanism(produitMech) &&
|
2020-04-23 16:39:56 +00:00
|
|
|
produitMech.name === 'produit' &&
|
|
|
|
typeof produitMech.explanation === 'object' &&
|
|
|
|
typeof produitMech.explanation.assiette === 'object' &&
|
|
|
|
typeof produitMech.explanation.plafond === 'object' &&
|
|
|
|
typeof produitMech.explanation.facteur === 'object' &&
|
|
|
|
typeof produitMech.explanation.taux === 'object'
|
|
|
|
)
|
2020-04-21 12:23:58 +00:00
|
|
|
}
|
2020-04-23 16:39:56 +00:00
|
|
|
|
2020-04-24 18:32:24 +00:00
|
|
|
type VariationsMech = AbstractMechanism & {
|
|
|
|
name: 'variations'
|
|
|
|
explanation: {
|
|
|
|
condition: ASTNode
|
|
|
|
consequence: ASTNode
|
|
|
|
}[]
|
|
|
|
}
|
|
|
|
export function isVariationsMech(node: ASTNode): node is VariationsMech {
|
|
|
|
const variationsMech = node as VariationsMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(variationsMech) &&
|
|
|
|
variationsMech.name === 'variations' &&
|
|
|
|
variationsMech.explanation instanceof Array &&
|
|
|
|
variationsMech.explanation.every(
|
|
|
|
variation =>
|
|
|
|
typeof variation === 'object' &&
|
|
|
|
variation.condition !== undefined &&
|
|
|
|
variation.consequence !== undefined
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type AllegementMech = AbstractMechanism & {
|
|
|
|
name: 'allègement'
|
|
|
|
explanation: {
|
|
|
|
abattement: ASTNode
|
|
|
|
assiette: ASTNode
|
|
|
|
décote:
|
|
|
|
| undefined
|
|
|
|
| {
|
|
|
|
plafond: ASTNode
|
|
|
|
taux: ASTNode
|
|
|
|
}
|
|
|
|
franchise: ASTNode
|
|
|
|
plafond: ASTNode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isAllegementMech(node: ASTNode): node is AllegementMech {
|
|
|
|
const allegementMech = node as AllegementMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(allegementMech) &&
|
|
|
|
allegementMech.name === 'allègement' &&
|
|
|
|
typeof allegementMech.explanation === 'object' &&
|
|
|
|
allegementMech.explanation.abattement !== undefined &&
|
|
|
|
allegementMech.explanation.assiette !== undefined &&
|
|
|
|
allegementMech.explanation.franchise !== undefined &&
|
|
|
|
allegementMech.explanation.plafond !== undefined &&
|
|
|
|
(allegementMech.explanation.décote === undefined ||
|
|
|
|
(typeof allegementMech.explanation.décote === 'object' &&
|
|
|
|
allegementMech.explanation.décote.plafond !== undefined &&
|
|
|
|
allegementMech.explanation.décote.taux !== undefined))
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type BaremeMech = AbstractMechanism & {
|
|
|
|
name: 'barème'
|
|
|
|
explanation: {
|
|
|
|
assiette: ASTNode
|
|
|
|
multiplicateur: ASTNode
|
|
|
|
tranches: {
|
|
|
|
plafond: ASTNode
|
|
|
|
taux: ASTNode
|
|
|
|
}[]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isBaremeMech(node: ASTNode): node is BaremeMech {
|
|
|
|
const baremeMech = node as BaremeMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(baremeMech) &&
|
|
|
|
baremeMech.name === 'barème' &&
|
|
|
|
typeof baremeMech.explanation === 'object' &&
|
|
|
|
baremeMech.explanation.assiette !== undefined &&
|
|
|
|
baremeMech.explanation.multiplicateur !== undefined &&
|
|
|
|
baremeMech.explanation.tranches instanceof Array &&
|
|
|
|
baremeMech.explanation.tranches.every(
|
|
|
|
tranche =>
|
|
|
|
typeof tranche === 'object' &&
|
|
|
|
tranche.plafond !== undefined &&
|
|
|
|
tranche.taux !== undefined
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type InversionNumMech<Names extends string> = AbstractMechanism & {
|
2020-04-24 18:32:24 +00:00
|
|
|
name: 'inversion numérique'
|
|
|
|
explanation: {
|
2020-05-06 15:26:45 +00:00
|
|
|
inversionCandidates: Array<Reference<Names>>
|
2020-04-24 18:32:24 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-06 15:26:45 +00:00
|
|
|
export function isInversionNumMech<Names extends string>(
|
2020-04-24 18:32:24 +00:00
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
): node is InversionNumMech<Names> {
|
|
|
|
const inversionNumMech = node as InversionNumMech<Names>
|
2020-04-24 18:32:24 +00:00
|
|
|
const isReferenceSpec = isReference as (
|
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
) => node is Reference<Names>
|
2020-04-24 18:32:24 +00:00
|
|
|
return (
|
|
|
|
isAbstractMechanism(inversionNumMech) &&
|
|
|
|
inversionNumMech.name === 'inversion numérique' &&
|
|
|
|
typeof inversionNumMech.explanation === 'object' &&
|
2020-04-24 20:00:42 +00:00
|
|
|
inversionNumMech.explanation.inversionCandidates instanceof Array &&
|
2020-05-06 15:10:10 +00:00
|
|
|
inversionNumMech.explanation.inversionCandidates.every(isReferenceSpec)
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ArrondiMech = AbstractMechanism & {
|
|
|
|
name: 'arrondi'
|
2020-04-24 20:00:42 +00:00
|
|
|
explanation: Record<keyof ArrondiExplanation, ASTNode>
|
2020-04-24 18:32:24 +00:00
|
|
|
}
|
|
|
|
export function isArrondiMech(node: ASTNode): node is ArrondiMech {
|
|
|
|
const arrondiMech = node as ArrondiMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(arrondiMech) &&
|
|
|
|
arrondiMech.name === 'arrondi' &&
|
|
|
|
typeof arrondiMech.explanation === 'object' &&
|
|
|
|
arrondiMech.explanation.decimals !== undefined &&
|
|
|
|
arrondiMech.explanation.value !== undefined
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type MaxMech = AbstractMechanism & {
|
|
|
|
name: 'le maximum de'
|
|
|
|
explanation: Array<ASTNode>
|
|
|
|
}
|
|
|
|
export function isMaxMech(node: ASTNode): node is MaxMech {
|
|
|
|
const maxMech = node as MaxMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(maxMech) &&
|
|
|
|
maxMech.name === 'le maximum de' &&
|
|
|
|
maxMech.explanation instanceof Array
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type MinMech = AbstractMechanism & {
|
|
|
|
name: 'le minimum de'
|
|
|
|
explanation: Array<ASTNode>
|
|
|
|
}
|
|
|
|
export function isMinMech(node: ASTNode): node is MinMech {
|
|
|
|
const minMech = node as MinMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(minMech) &&
|
|
|
|
minMech.name === 'le minimum de' &&
|
|
|
|
minMech.explanation instanceof Array
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ComposantesMech = AbstractMechanism & {
|
|
|
|
name: 'composantes'
|
|
|
|
explanation: Array<ASTNode>
|
|
|
|
}
|
|
|
|
export function isComposantesMech(node: ASTNode): node is ComposantesMech {
|
|
|
|
const composantesMech = node as ComposantesMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(composantesMech) &&
|
|
|
|
composantesMech.name === 'composantes' &&
|
|
|
|
composantesMech.explanation instanceof Array
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type UneConditionsMech = AbstractMechanism & {
|
|
|
|
name: 'une de ces conditions'
|
|
|
|
explanation: Array<ASTNode>
|
|
|
|
}
|
|
|
|
export function isUneConditionsMech(node: ASTNode): node is UneConditionsMech {
|
|
|
|
const uneConditionsMech = node as UneConditionsMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(uneConditionsMech) &&
|
|
|
|
uneConditionsMech.name === 'une de ces conditions' &&
|
|
|
|
uneConditionsMech.explanation instanceof Array
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ToutesConditionsMech = AbstractMechanism & {
|
|
|
|
name: 'toutes ces conditions'
|
|
|
|
explanation: Array<ASTNode>
|
|
|
|
}
|
|
|
|
export function isToutesConditionsMech(
|
|
|
|
node: ASTNode
|
|
|
|
): node is ToutesConditionsMech {
|
|
|
|
const toutesConditionsMech = node as ToutesConditionsMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(toutesConditionsMech) &&
|
|
|
|
toutesConditionsMech.name === 'toutes ces conditions' &&
|
|
|
|
toutesConditionsMech.explanation instanceof Array
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type SyncMech = AbstractMechanism & {
|
|
|
|
name: 'synchronisation'
|
|
|
|
API: {}
|
|
|
|
}
|
|
|
|
export function isSyncMech(node: ASTNode): node is SyncMech {
|
|
|
|
const syncMech = node as SyncMech
|
|
|
|
return isAbstractMechanism(syncMech) && syncMech.name === 'synchronisation'
|
|
|
|
}
|
|
|
|
|
|
|
|
type GrilleMech = AbstractMechanism & {
|
|
|
|
name: 'grille'
|
|
|
|
explanation: {
|
|
|
|
assiette: ASTNode
|
|
|
|
multiplicateur: ASTNode
|
|
|
|
tranches: {
|
|
|
|
montant: ASTNode
|
|
|
|
plafond: ASTNode
|
|
|
|
}[]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isGrilleMech(node: ASTNode): node is GrilleMech {
|
|
|
|
const grilleMech = node as GrilleMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(grilleMech) &&
|
|
|
|
grilleMech.name === 'grille' &&
|
|
|
|
typeof grilleMech.explanation === 'object' &&
|
|
|
|
grilleMech.explanation.assiette !== undefined &&
|
|
|
|
grilleMech.explanation.multiplicateur !== undefined &&
|
|
|
|
grilleMech.explanation.tranches instanceof Array &&
|
|
|
|
grilleMech.explanation.tranches.every(
|
|
|
|
tranche =>
|
|
|
|
typeof tranche === 'object' &&
|
|
|
|
tranche.montant !== undefined &&
|
|
|
|
tranche.plafond !== undefined
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type TauxProgMech = AbstractMechanism & {
|
|
|
|
name: 'taux progressif'
|
|
|
|
explanation: {
|
|
|
|
assiette: ASTNode
|
|
|
|
multiplicateur: ASTNode
|
|
|
|
tranches: {
|
|
|
|
plafond: ASTNode
|
|
|
|
taux: ASTNode
|
|
|
|
}[]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isTauxProgMech(node: ASTNode): node is TauxProgMech {
|
|
|
|
const tauxProgMech = node as TauxProgMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(tauxProgMech) &&
|
|
|
|
tauxProgMech.name === 'taux progressif' &&
|
|
|
|
typeof tauxProgMech.explanation === 'object' &&
|
|
|
|
tauxProgMech.explanation.assiette !== undefined &&
|
|
|
|
tauxProgMech.explanation.multiplicateur !== undefined &&
|
|
|
|
tauxProgMech.explanation.tranches instanceof Array &&
|
|
|
|
tauxProgMech.explanation.tranches.every(
|
|
|
|
tranche =>
|
|
|
|
typeof tranche === 'object' &&
|
|
|
|
tranche.plafond !== undefined &&
|
|
|
|
tranche.taux !== undefined
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
type DureeMech = AbstractMechanism & {
|
|
|
|
name: 'Durée'
|
|
|
|
explanation: {
|
|
|
|
depuis: ASTNode
|
|
|
|
"jusqu'à": ASTNode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export function isDureeMech(node: ASTNode): node is DureeMech {
|
|
|
|
const dureeMech = node as DureeMech
|
|
|
|
return (
|
|
|
|
isAbstractMechanism(dureeMech) &&
|
|
|
|
dureeMech.name === 'Durée' &&
|
|
|
|
typeof dureeMech.explanation === 'object' &&
|
|
|
|
dureeMech.explanation.depuis !== undefined &&
|
|
|
|
dureeMech.explanation["jusqu'à"] !== undefined
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
type AnyMechanism<Names extends string> =
|
|
|
|
| RecalculMech<Names>
|
2020-04-24 19:32:05 +00:00
|
|
|
| EncadrementMech
|
|
|
|
| SommeMech
|
|
|
|
| ProduitMech
|
|
|
|
| VariationsMech
|
|
|
|
| AllegementMech
|
|
|
|
| BaremeMech
|
2020-05-06 15:26:45 +00:00
|
|
|
| InversionNumMech<Names>
|
2020-04-24 19:32:05 +00:00
|
|
|
| ArrondiMech
|
|
|
|
| MaxMech
|
|
|
|
| MinMech
|
|
|
|
| ComposantesMech
|
|
|
|
| UneConditionsMech
|
|
|
|
| ToutesConditionsMech
|
|
|
|
| SyncMech
|
|
|
|
| GrilleMech
|
|
|
|
| TauxProgMech
|
|
|
|
| DureeMech
|
2020-05-06 15:26:45 +00:00
|
|
|
export function isAnyMechanism<Names extends string>(
|
2020-04-24 19:32:05 +00:00
|
|
|
node: ASTNode
|
2020-05-06 15:26:45 +00:00
|
|
|
): node is AnyMechanism<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
return (
|
2020-05-06 15:26:45 +00:00
|
|
|
isRecalculMech<Names>(node) ||
|
2020-04-24 18:32:24 +00:00
|
|
|
isEncadrementMech(node) ||
|
|
|
|
isSommeMech(node) ||
|
|
|
|
isProduitMech(node) ||
|
|
|
|
isVariationsMech(node) ||
|
|
|
|
isAllegementMech(node) ||
|
|
|
|
isBaremeMech(node) ||
|
2020-05-06 15:26:45 +00:00
|
|
|
isInversionNumMech<Names>(node) ||
|
2020-04-24 18:32:24 +00:00
|
|
|
isArrondiMech(node) ||
|
|
|
|
isMaxMech(node) ||
|
|
|
|
isMinMech(node) ||
|
|
|
|
isComposantesMech(node) ||
|
|
|
|
isUneConditionsMech(node) ||
|
|
|
|
isToutesConditionsMech(node) ||
|
|
|
|
isSyncMech(node) ||
|
|
|
|
isGrilleMech(node) ||
|
|
|
|
isTauxProgMech(node) ||
|
|
|
|
isDureeMech(node)
|
|
|
|
)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
type RuleDependencies<Names extends string> = Array<Names>
|
|
|
|
|
|
|
|
export function ruleDepsOfNode<Names extends string>(
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName: Names,
|
2020-04-20 21:35:03 +00:00
|
|
|
node: ASTNode
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
|
|
|
function ruleDepsOfApplicableSi(
|
2020-04-24 19:45:25 +00:00
|
|
|
applicableSi: ApplicableSi
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
|
|
|
return ruleDepsOfNode(ruleName, applicableSi.explanation)
|
2020-04-24 19:45:25 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfNonApplicableSi(
|
2020-04-24 19:45:25 +00:00
|
|
|
nonApplicableSi: NonApplicableSi
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
|
|
|
return ruleDepsOfNode(ruleName, nonApplicableSi.explanation)
|
2020-04-24 19:45:25 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfFormule(formule: Formule<Names>): RuleDependencies<Names> {
|
|
|
|
return ruleDepsOfNode(ruleName, formule.explanation)
|
2020-04-24 19:32:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfValue(value: Value): RuleDependencies<Names> {
|
2020-04-20 21:35:03 +00:00
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfOperation(operation: Operation): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
return operation.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-23 16:39:56 +00:00
|
|
|
)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfPossibilities(
|
2020-04-20 21:35:03 +00:00
|
|
|
possibilities: Possibilities
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
return []
|
|
|
|
}
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfPossibilities2(
|
2020-04-24 18:32:24 +00:00
|
|
|
possibilities: Possibilities2
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-20 21:35:03 +00:00
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfReference(
|
2020-05-06 15:26:45 +00:00
|
|
|
reference: Reference<Names>
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-21 20:56:40 +00:00
|
|
|
return [reference.dottedName]
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfRecalculMech(
|
2020-05-06 15:26:45 +00:00
|
|
|
recalculMech: RecalculMech<Names>
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-24 19:32:05 +00:00
|
|
|
return [recalculMech.explanation.recalcul.partialReference]
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfEncadrementMech(
|
2020-04-23 16:39:56 +00:00
|
|
|
encadrementMech: EncadrementMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = [
|
|
|
|
encadrementMech.explanation.plafond,
|
|
|
|
encadrementMech.explanation.plancher,
|
|
|
|
encadrementMech.explanation.valeur
|
|
|
|
].flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-23 16:39:56 +00:00
|
|
|
)
|
2020-04-24 18:32:24 +00:00
|
|
|
return result
|
2020-04-23 16:39:56 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfSommeMech(sommeMech: SommeMech): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = sommeMech.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-23 16:39:56 +00:00
|
|
|
)
|
2020-04-24 18:32:24 +00:00
|
|
|
return result
|
2020-04-23 16:39:56 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfProduitMech(
|
2020-04-23 16:39:56 +00:00
|
|
|
produitMech: ProduitMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = [
|
|
|
|
produitMech.explanation.assiette,
|
|
|
|
produitMech.explanation.plafond,
|
|
|
|
produitMech.explanation.facteur,
|
|
|
|
produitMech.explanation.taux
|
|
|
|
].flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfVariationsMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
variationsMech: VariationsMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
function ruleOfVariation({
|
|
|
|
condition,
|
|
|
|
consequence
|
|
|
|
}: {
|
|
|
|
condition: ASTNode
|
|
|
|
consequence: ASTNode
|
2020-05-08 18:12:50 +00:00
|
|
|
}): RuleDependencies<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
return R.concat(
|
2020-05-08 18:12:50 +00:00
|
|
|
ruleDepsOfNode<Names>(ruleName, condition),
|
|
|
|
ruleDepsOfNode<Names>(ruleName, consequence)
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
}
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = variationsMech.explanation.flatMap(ruleOfVariation)
|
2020-04-24 18:32:24 +00:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfAllegementMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
allegementMech: AllegementMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
const subNodes = R.concat(
|
|
|
|
[
|
|
|
|
allegementMech.explanation.abattement,
|
|
|
|
allegementMech.explanation.assiette,
|
|
|
|
allegementMech.explanation.franchise,
|
|
|
|
allegementMech.explanation.plafond
|
|
|
|
],
|
|
|
|
allegementMech.explanation.décote
|
|
|
|
? [
|
|
|
|
allegementMech.explanation.décote.plafond,
|
|
|
|
allegementMech.explanation.décote.taux
|
|
|
|
]
|
|
|
|
: []
|
|
|
|
)
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = subNodes.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfBaremeMech(
|
|
|
|
baremeMech: BaremeMech
|
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const tranchesNodes = baremeMech.explanation.tranches.flatMap(
|
|
|
|
({ plafond, taux }) => [plafond, taux]
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = R.concat(
|
|
|
|
[baremeMech.explanation.assiette, baremeMech.explanation.multiplicateur],
|
|
|
|
tranchesNodes
|
|
|
|
).flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns 0 dependency for _inversion numérique_ as it's not creating a logical dependency.
|
|
|
|
*/
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfInversionNumMech(
|
2020-05-06 15:26:45 +00:00
|
|
|
inversionNumMech: InversionNumMech<Names>
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfArrondiMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
arrondiMech: ArrondiMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = [
|
|
|
|
arrondiMech.explanation.decimals,
|
|
|
|
arrondiMech.explanation.value
|
|
|
|
].flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfMaxMech(maxMech: MaxMech): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = maxMech.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfMinMech(minMech: MinMech): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = minMech.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfComposantesMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
composantesMech: ComposantesMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = composantesMech.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfUneConditionsMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
uneConditionsMech: UneConditionsMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = uneConditionsMech.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfToutesConditionsMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
toutesConditionsMech: ToutesConditionsMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = toutesConditionsMech.explanation.flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfSyncMech(_: SyncMech): RuleDependencies<Names> {
|
2020-04-24 18:32:24 +00:00
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfGrilleMech(
|
|
|
|
grilleMech: GrilleMech
|
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const tranchesNodes = grilleMech.explanation.tranches.flatMap(
|
|
|
|
({ montant, plafond }) => [montant, plafond]
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = R.concat(
|
|
|
|
[grilleMech.explanation.assiette, grilleMech.explanation.multiplicateur],
|
|
|
|
tranchesNodes
|
|
|
|
).flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfTauxProgMech(
|
2020-04-24 18:32:24 +00:00
|
|
|
tauxProgMech: TauxProgMech
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const tranchesNodes = tauxProgMech.explanation.tranches.flatMap(
|
|
|
|
({ plafond, taux }) => [plafond, taux]
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = R.concat(
|
|
|
|
[
|
|
|
|
tauxProgMech.explanation.assiette,
|
|
|
|
tauxProgMech.explanation.multiplicateur
|
|
|
|
],
|
|
|
|
tranchesNodes
|
|
|
|
).flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfDureeMech(dureeMech: DureeMech): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const result = [
|
|
|
|
dureeMech.explanation.depuis,
|
|
|
|
dureeMech.explanation["jusqu'à"]
|
|
|
|
].flatMap(
|
2020-05-08 18:12:50 +00:00
|
|
|
R.partial<Names, ASTNode, RuleDependencies<Names>>(ruleDepsOfNode, [
|
2020-05-08 17:24:05 +00:00
|
|
|
ruleName
|
2020-05-06 15:10:10 +00:00
|
|
|
])
|
2020-04-24 18:32:24 +00:00
|
|
|
)
|
2020-04-23 16:39:56 +00:00
|
|
|
return result
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
let result
|
2020-04-24 19:45:25 +00:00
|
|
|
if (isApplicableSi(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfApplicableSi(node)
|
2020-04-24 19:45:25 +00:00
|
|
|
} else if (isNonApplicableSi(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfNonApplicableSi(node)
|
2020-05-06 15:26:45 +00:00
|
|
|
} else if (isFormule<Names>(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfFormule(node)
|
2020-04-24 19:32:05 +00:00
|
|
|
} else if (isValue(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfValue(node)
|
2020-04-20 21:35:03 +00:00
|
|
|
} else if (isOperation(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfOperation(node)
|
2020-05-06 15:26:45 +00:00
|
|
|
} else if (isReference<Names>(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfReference(node)
|
2020-04-20 21:35:03 +00:00
|
|
|
} else if (isPossibilities(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfPossibilities(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isPossibilities2(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfPossibilities2(node)
|
2020-05-06 15:26:45 +00:00
|
|
|
} else if (isRecalculMech<Names>(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfRecalculMech(node)
|
2020-04-23 16:39:56 +00:00
|
|
|
} else if (isEncadrementMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfEncadrementMech(node)
|
2020-04-23 16:39:56 +00:00
|
|
|
} else if (isSommeMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfSommeMech(node)
|
2020-04-23 16:39:56 +00:00
|
|
|
} else if (isProduitMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfProduitMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isVariationsMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfVariationsMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isAllegementMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfAllegementMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isBaremeMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfBaremeMech(node)
|
2020-05-06 15:26:45 +00:00
|
|
|
} else if (isInversionNumMech<Names>(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfInversionNumMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isArrondiMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfArrondiMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isMaxMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfMaxMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isMinMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfMinMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isComposantesMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfComposantesMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isUneConditionsMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfUneConditionsMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isToutesConditionsMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfToutesConditionsMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isSyncMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfSyncMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isGrilleMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfGrilleMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isTauxProgMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfTauxProgMech(node)
|
2020-04-24 18:32:24 +00:00
|
|
|
} else if (isDureeMech(node)) {
|
2020-05-08 18:12:50 +00:00
|
|
|
result = ruleDepsOfDureeMech(node)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
2020-04-24 18:32:24 +00:00
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
if (result === undefined) {
|
|
|
|
throw new Error(
|
|
|
|
`This node doesn't have a visitor method defined: ${JSON.stringify(
|
|
|
|
node,
|
|
|
|
null,
|
|
|
|
4
|
|
|
|
)}`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return result
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 18:12:50 +00:00
|
|
|
function ruleDepsOfRuleNode<Names extends string>(
|
2020-05-06 15:26:45 +00:00
|
|
|
rule: RuleNode<Names>
|
2020-05-08 18:12:50 +00:00
|
|
|
): RuleDependencies<Names> {
|
2020-05-06 15:10:10 +00:00
|
|
|
const subNodes = [
|
|
|
|
rule.formule,
|
|
|
|
rule['applicable si'],
|
|
|
|
rule['non applicable si']
|
|
|
|
].filter(x => x !== undefined) as Array<ASTNode>
|
|
|
|
const dependenciesLists = subNodes.map(x =>
|
2020-05-08 18:12:50 +00:00
|
|
|
ruleDepsOfNode<Names>(rule.dottedName, x)
|
2020-04-24 19:45:25 +00:00
|
|
|
)
|
2020-05-06 15:10:10 +00:00
|
|
|
return dependenciesLists.flat(1)
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
export function buildRulesDependencies<Names extends string>(
|
|
|
|
parsedRules: ParsedRules<Names>
|
2020-05-08 18:12:50 +00:00
|
|
|
): Array<[Names, RuleDependencies<Names>]> {
|
2020-04-21 20:56:40 +00:00
|
|
|
// This stringPairs thing is necessary because `toPairs` is strictly considering that
|
|
|
|
// object keys are strings (same for `Object.entries`). Maybe we should build our own
|
|
|
|
// `toPairs`?
|
2020-05-06 15:26:45 +00:00
|
|
|
const stringPairs: Array<[string, RuleNode<Names>]> = Object.entries(
|
2020-05-06 15:10:10 +00:00
|
|
|
parsedRules
|
|
|
|
)
|
2020-05-06 15:26:45 +00:00
|
|
|
const pairs: Array<[Names, RuleNode<Names>]> = stringPairs as Array<
|
|
|
|
[Names, RuleNode<Names>]
|
2020-04-21 20:56:40 +00:00
|
|
|
>
|
2020-05-06 15:10:10 +00:00
|
|
|
|
2020-05-06 15:26:45 +00:00
|
|
|
return pairs.map(([dottedName, ruleNode]: [Names, RuleNode<Names>]): [
|
|
|
|
Names,
|
2020-05-08 18:12:50 +00:00
|
|
|
RuleDependencies<Names>
|
|
|
|
] => [dottedName, ruleDepsOfRuleNode<Names>(ruleNode)])
|
2020-04-20 21:35:03 +00:00
|
|
|
}
|