WIP ⚙️ Detect cycles: finish all node types and visitors
parent
dba5237a74
commit
47f1620e5d
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import R from 'ramda'
|
||||
import { ArrondiExplanation } from './mecanisms/arrondi'
|
||||
import { ParsedRule, ParsedRules } from './types'
|
||||
|
||||
type OnOff = 'oui' | 'non'
|
||||
|
@ -24,15 +25,14 @@ type ASTNode = { [_: string]: {} | undefined }
|
|||
type RuleNode<Name extends string> = /* ASTNode & */ ParsedRule<Name>
|
||||
|
||||
type Value = ASTNode & {
|
||||
nodeValue: number | string
|
||||
constant?: boolean
|
||||
nodeValue: number | string | boolean
|
||||
}
|
||||
export function isValue(node: ASTNode): node is Value {
|
||||
const value = node as Value
|
||||
return (
|
||||
(typeof value.nodeValue === 'string' ||
|
||||
typeof value.nodeValue === 'number') &&
|
||||
(value.constant === undefined || typeof value.constant === 'boolean')
|
||||
typeof value.nodeValue === 'string' ||
|
||||
typeof value.nodeValue === 'number' ||
|
||||
typeof value.nodeValue === 'boolean'
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -62,13 +62,29 @@ export function isPossibilities(node: ASTNode): node is Possibilities {
|
|||
isOnOff(possibilities['une possibilité'])
|
||||
)
|
||||
}
|
||||
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 (
|
||||
R.all(
|
||||
([k, v]) => isNaN(parseInt(k, 10)) || typeof v === 'string',
|
||||
R.toPairs(possibilities2)
|
||||
) &&
|
||||
(possibilities2['choix obligatoire'] === undefined ||
|
||||
isOnOff(possibilities2['choix obligatoire'])) &&
|
||||
isOnOff(possibilities2['une possibilité'])
|
||||
)
|
||||
}
|
||||
|
||||
type Reference<Name extends string> = ASTNode & {
|
||||
category: 'reference'
|
||||
name: Name
|
||||
partialReference: Name
|
||||
dottedName: Name
|
||||
unit: {} | undefined
|
||||
}
|
||||
export function isReference<Name extends string>(
|
||||
node: ASTNode
|
||||
|
@ -92,10 +108,13 @@ export function isRecalcul<Name extends string>(
|
|||
node: ASTNode
|
||||
): node is Recalcul<Name> {
|
||||
const recalcul = node as Recalcul<Name>
|
||||
const isReferenceSpec = isReference as (
|
||||
node: ASTNode
|
||||
) => node is Reference<Name>
|
||||
return (
|
||||
typeof recalcul.explanation === 'object' &&
|
||||
typeof recalcul.explanation.recalcul === 'object' &&
|
||||
isReference(recalcul.explanation.recalcul as ASTNode) &&
|
||||
isReferenceSpec(recalcul.explanation.recalcul as ASTNode) &&
|
||||
typeof recalcul.explanation.amendedSituation === 'object'
|
||||
// [XXX] - We would like to do
|
||||
// && R.all(isDottedName, R.keys(recalcul.explanation.amendedSituation))
|
||||
|
@ -119,18 +138,21 @@ export function isAbstractMechanism(node: ASTNode): node is AbstractMechanism {
|
|||
|
||||
type EncadrementMech = AbstractMechanism & {
|
||||
name: 'encadrement'
|
||||
valeur: {
|
||||
explanation: Array<ASTNode>
|
||||
[_: string]: {} | undefined
|
||||
explanation: {
|
||||
valeur: ASTNode
|
||||
plafond: ASTNode
|
||||
plancher: ASTNode
|
||||
}
|
||||
}
|
||||
export function isEncadrementMech(node: ASTNode): node is EncadrementMech {
|
||||
const encadrementMech = node as EncadrementMech
|
||||
return (
|
||||
isAbstractMechanism(encadrementMech) &&
|
||||
typeof encadrementMech.valeur === 'object' &&
|
||||
encadrementMech.valeur.explanation instanceof Array &&
|
||||
encadrementMech.name === 'encadrement'
|
||||
encadrementMech.name == 'encadrement' &&
|
||||
typeof encadrementMech.explanation === 'object' &&
|
||||
encadrementMech.explanation.valeur !== undefined &&
|
||||
encadrementMech.explanation.plafond !== undefined &&
|
||||
encadrementMech.explanation.plancher !== undefined
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -143,14 +165,12 @@ export function isSommeMech(node: ASTNode): node is SommeMech {
|
|||
return (
|
||||
isAbstractMechanism(sommeMech) &&
|
||||
sommeMech.name === 'somme' &&
|
||||
typeof sommeMech.explanation === 'object'
|
||||
sommeMech.explanation instanceof Array
|
||||
)
|
||||
}
|
||||
|
||||
type ProduitMech = AbstractMechanism & {
|
||||
name: 'produit'
|
||||
type: 'numeric'
|
||||
unit: {}
|
||||
explanation: {
|
||||
assiette: ASTNode
|
||||
plafond: ASTNode
|
||||
|
@ -161,9 +181,8 @@ type ProduitMech = AbstractMechanism & {
|
|||
export function isProduitMech(node: ASTNode): node is ProduitMech {
|
||||
const produitMech = node as ProduitMech
|
||||
return (
|
||||
isAbstractMechanism(produitMech) &&
|
||||
produitMech.name === 'produit' &&
|
||||
produitMech.type === 'numeric' &&
|
||||
produitMech.unit !== undefined &&
|
||||
typeof produitMech.explanation === 'object' &&
|
||||
typeof produitMech.explanation.assiette === 'object' &&
|
||||
typeof produitMech.explanation.plafond === 'object' &&
|
||||
|
@ -172,15 +191,308 @@ export function isProduitMech(node: ASTNode): node is ProduitMech {
|
|||
)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
type InversionNumMech<Name extends string> = AbstractMechanism & {
|
||||
name: 'inversion numérique'
|
||||
avec: Array<string> // Actually: short dotted name
|
||||
explanation: {
|
||||
avec: Array<Reference<Name>>
|
||||
}
|
||||
}
|
||||
export function isInversionNumMech<Name extends string>(
|
||||
node: ASTNode
|
||||
): node is InversionNumMech<Name> {
|
||||
const inversionNumMech = node as InversionNumMech<Name>
|
||||
const isReferenceSpec = isReference as (
|
||||
node: ASTNode
|
||||
) => node is Reference<Name>
|
||||
return (
|
||||
isAbstractMechanism(inversionNumMech) &&
|
||||
inversionNumMech.name === 'inversion numérique' &&
|
||||
inversionNumMech.avec instanceof Array &&
|
||||
typeof inversionNumMech.explanation === 'object' &&
|
||||
inversionNumMech.explanation.avec instanceof Array &&
|
||||
R.all(isReferenceSpec, inversionNumMech.explanation.avec)
|
||||
)
|
||||
}
|
||||
|
||||
type ArrondiMech = AbstractMechanism & {
|
||||
name: 'arrondi'
|
||||
explanation: ArrondiExplanation
|
||||
}
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
type AnyMechanism = EncadrementMech | SommeMech
|
||||
export function isAnyMechanism(node: ASTNode): node is AnyMechanism {
|
||||
return isEncadrementMech(node) || isSommeMech(node) || isProduitMech(node)
|
||||
return (
|
||||
isEncadrementMech(node) ||
|
||||
isSommeMech(node) ||
|
||||
isProduitMech(node) ||
|
||||
isVariationsMech(node) ||
|
||||
isAllegementMech(node) ||
|
||||
isBaremeMech(node) ||
|
||||
isInversionNumMech(node) ||
|
||||
isArrondiMech(node) ||
|
||||
isMaxMech(node) ||
|
||||
isMinMech(node) ||
|
||||
isComposantesMech(node) ||
|
||||
isUneConditionsMech(node) ||
|
||||
isToutesConditionsMech(node) ||
|
||||
isSyncMech(node) ||
|
||||
isGrilleMech(node) ||
|
||||
isTauxProgMech(node) ||
|
||||
isDureeMech(node)
|
||||
)
|
||||
}
|
||||
|
||||
type FormuleNode<Name extends string> =
|
||||
| Value
|
||||
| Operation
|
||||
| Possibilities
|
||||
| Possibilities2
|
||||
| Reference<Name>
|
||||
| Recalcul<Name>
|
||||
| AnyMechanism
|
||||
|
@ -192,16 +504,14 @@ export function isFormuleNode<Name extends string>(
|
|||
isOperation(node) ||
|
||||
isReference(node) ||
|
||||
isPossibilities(node) ||
|
||||
isPossibilities2(node) ||
|
||||
isRecalcul(node) ||
|
||||
isAnyMechanism(node)
|
||||
)
|
||||
}
|
||||
|
||||
function logVisit(
|
||||
depth: number,
|
||||
typeName: string,
|
||||
obj: string | number | object
|
||||
): void {
|
||||
function logVisit(depth: number, typeName: string, obj: {}): void {
|
||||
return
|
||||
let cleanRepr = obj
|
||||
if (typeof obj === 'object') {
|
||||
cleanRepr = JSON.stringify(obj, null)
|
||||
|
@ -235,7 +545,18 @@ export function ruleDependenciesOfNode<Name extends string>(
|
|||
depth: number,
|
||||
possibilities: Possibilities
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'possibilities', possibilities.possibilités.join(', '))
|
||||
logVisit(depth, 'possibilities', possibilities.possibilités)
|
||||
return []
|
||||
}
|
||||
function ruleDependenciesOfPossibilities2(
|
||||
depth: number,
|
||||
possibilities: Possibilities2
|
||||
): Array<Name> {
|
||||
logVisit(
|
||||
depth,
|
||||
'possibilities2',
|
||||
R.filter(([k, _]) => !isNaN(parseInt(k, 10)), R.toPairs(possibilities))
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -263,68 +584,359 @@ export function ruleDependenciesOfNode<Name extends string>(
|
|||
depth: number,
|
||||
encadrementMech: EncadrementMech
|
||||
): Array<Name> {
|
||||
debugger // [XXX] - correct the type, guard and visit logger
|
||||
logVisit(depth, 'encadrement mechanism', '??') // [XXX]
|
||||
return R.chain(
|
||||
logVisit(depth, 'encadrement mechanism', '??')
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
encadrementMech.valeur.explanation
|
||||
[
|
||||
encadrementMech.explanation.plafond,
|
||||
encadrementMech.explanation.plancher,
|
||||
encadrementMech.explanation.valeur
|
||||
]
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfSommeMech(
|
||||
depth: number,
|
||||
sommeMech: SommeMech
|
||||
): Array<Name> {
|
||||
debugger // [XXX] - correct the type, guard and visit logger
|
||||
logVisit(depth, 'somme mech', '??') // [XXX]
|
||||
return R.chain(
|
||||
logVisit(depth, 'somme mech', '??')
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
sommeMech.explanation
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfProduitMech(
|
||||
depth: number,
|
||||
produitMech: ProduitMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'produit mech', '')
|
||||
const result = R.chain<Array<Name>, Name>(R.identity, [
|
||||
ruleDependenciesOfNode(depth + 1, produitMech.explanation.assiette),
|
||||
ruleDependenciesOfNode(depth + 1, produitMech.explanation.plafond),
|
||||
ruleDependenciesOfNode(depth + 1, produitMech.explanation.facteur),
|
||||
ruleDependenciesOfNode(depth + 1, produitMech.explanation.taux)
|
||||
])
|
||||
logVisit(depth, 'produit mech', '??')
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
[
|
||||
produitMech.explanation.assiette,
|
||||
produitMech.explanation.plafond,
|
||||
produitMech.explanation.facteur,
|
||||
produitMech.explanation.taux
|
||||
]
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfVariationsMech(
|
||||
depth: number,
|
||||
variationsMech: VariationsMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'variations mech', '??')
|
||||
|
||||
function ruleOfVariation({
|
||||
condition,
|
||||
consequence
|
||||
}: {
|
||||
condition: ASTNode
|
||||
consequence: ASTNode
|
||||
}): Array<Name> {
|
||||
return R.concat(
|
||||
ruleDependenciesOfNode<Name>(depth + 1, condition),
|
||||
ruleDependenciesOfNode<Name>(depth + 1, consequence)
|
||||
)
|
||||
}
|
||||
const result = R.chain(ruleOfVariation, variationsMech.explanation)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfAllegementMech(
|
||||
depth: number,
|
||||
allegementMech: AllegementMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'allegement mech', '??')
|
||||
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
|
||||
]
|
||||
: []
|
||||
)
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
subNodes
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfBaremeMech(
|
||||
depth: number,
|
||||
baremeMech: BaremeMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'barème mech', '??')
|
||||
const tranchesNodes = R.chain(
|
||||
({ plafond, taux }) => [plafond, taux],
|
||||
baremeMech.explanation.tranches
|
||||
)
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
R.concat(
|
||||
[
|
||||
baremeMech.explanation.assiette,
|
||||
baremeMech.explanation.multiplicateur
|
||||
],
|
||||
tranchesNodes
|
||||
)
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 dependency for _inversion numérique_ as it's not creating a logical dependency.
|
||||
*/
|
||||
function ruleDependenciesOfInversionNumMech(
|
||||
depth: number,
|
||||
inversionNumMech: InversionNumMech<Name>
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'inversion numérique', inversionNumMech.avec)
|
||||
return []
|
||||
}
|
||||
|
||||
function ruleDependenciesOfArrondiMech(
|
||||
depth: number,
|
||||
arrondiMech: ArrondiMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'arrondi mech', '??')
|
||||
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
[arrondiMech.explanation.decimals, arrondiMech.explanation.value]
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfMaxMech(
|
||||
depth: number,
|
||||
maxMech: MaxMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'max mech', '??')
|
||||
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
maxMech.explanation
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfMinMech(
|
||||
depth: number,
|
||||
minMech: MinMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'min mech', '??')
|
||||
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
minMech.explanation
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfComposantesMech(
|
||||
depth: number,
|
||||
composantesMech: ComposantesMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'composantes mech', '??')
|
||||
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
composantesMech.explanation
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfUneConditionsMech(
|
||||
depth: number,
|
||||
uneConditionsMech: UneConditionsMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'une conditions mech', '??')
|
||||
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
uneConditionsMech.explanation
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfToutesConditionsMech(
|
||||
depth: number,
|
||||
toutesConditionsMech: ToutesConditionsMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'toutes conditions mech', '??')
|
||||
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
toutesConditionsMech.explanation
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfSyncMech(depth: number, _: SyncMech): Array<Name> {
|
||||
logVisit(depth, 'sync mech', '??')
|
||||
return []
|
||||
}
|
||||
|
||||
function ruleDependenciesOfGrilleMech(
|
||||
depth: number,
|
||||
grilleMech: GrilleMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'grille mech', '??')
|
||||
const tranchesNodes = R.chain(
|
||||
({ montant, plafond }) => [montant, plafond],
|
||||
grilleMech.explanation.tranches
|
||||
)
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
R.concat(
|
||||
[
|
||||
grilleMech.explanation.assiette,
|
||||
grilleMech.explanation.multiplicateur
|
||||
],
|
||||
tranchesNodes
|
||||
)
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfTauxProgMech(
|
||||
depth: number,
|
||||
tauxProgMech: TauxProgMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'taux progressif mech', '??')
|
||||
const tranchesNodes = R.chain(
|
||||
({ plafond, taux }) => [plafond, taux],
|
||||
tauxProgMech.explanation.tranches
|
||||
)
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
R.concat(
|
||||
[
|
||||
tauxProgMech.explanation.assiette,
|
||||
tauxProgMech.explanation.multiplicateur
|
||||
],
|
||||
tranchesNodes
|
||||
)
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
function ruleDependenciesOfDureeMech(
|
||||
depth: number,
|
||||
dureeMech: DureeMech
|
||||
): Array<Name> {
|
||||
logVisit(depth, 'durée mech', '??')
|
||||
const result = R.chain(
|
||||
R.partial<number, ASTNode, Array<Name>>(ruleDependenciesOfNode, [
|
||||
depth + 1
|
||||
]),
|
||||
[dureeMech.explanation.depuis, dureeMech.explanation["jusqu'à"]]
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
if (isValue(node)) {
|
||||
return ruleDependenciesOfValue(depth, node as Value)
|
||||
return ruleDependenciesOfValue(depth, node)
|
||||
} else if (isOperation(node)) {
|
||||
return ruleDependenciesOfOperation(depth, node as Operation)
|
||||
} else if (isReference(node)) {
|
||||
return ruleDependenciesOfReference(depth, node as Reference<Name>)
|
||||
return ruleDependenciesOfOperation(depth, node)
|
||||
} else if (isReference<Name>(node)) {
|
||||
return ruleDependenciesOfReference(depth, node)
|
||||
} else if (isPossibilities(node)) {
|
||||
return ruleDependenciesOfPossibilities(depth, node as Possibilities)
|
||||
} else if (isRecalcul(node)) {
|
||||
return ruleDependenciesOfRecalcul(depth, node as Recalcul<Name>)
|
||||
return ruleDependenciesOfPossibilities(depth, node)
|
||||
} else if (isPossibilities2(node)) {
|
||||
return ruleDependenciesOfPossibilities2(depth, node)
|
||||
} else if (isRecalcul<Name>(node)) {
|
||||
return ruleDependenciesOfRecalcul(depth, node)
|
||||
} else if (isEncadrementMech(node)) {
|
||||
return ruleDependenciesOfEncadrementMech(depth, node as EncadrementMech)
|
||||
return ruleDependenciesOfEncadrementMech(depth, node)
|
||||
} else if (isSommeMech(node)) {
|
||||
return ruleDependenciesOfSommeMech(depth, node as SommeMech)
|
||||
return ruleDependenciesOfSommeMech(depth, node)
|
||||
} else if (isProduitMech(node)) {
|
||||
return ruleDependenciesOfProduitMech(depth, node)
|
||||
} else if (isVariationsMech(node)) {
|
||||
return ruleDependenciesOfVariationsMech(depth, node)
|
||||
} else if (isAllegementMech(node)) {
|
||||
return ruleDependenciesOfAllegementMech(depth, node)
|
||||
} else if (isBaremeMech(node)) {
|
||||
return ruleDependenciesOfBaremeMech(depth, node)
|
||||
} else if (isInversionNumMech<Name>(node)) {
|
||||
return ruleDependenciesOfInversionNumMech(depth, node)
|
||||
} else if (isArrondiMech(node)) {
|
||||
return ruleDependenciesOfArrondiMech(depth, node)
|
||||
} else if (isMaxMech(node)) {
|
||||
return ruleDependenciesOfMaxMech(depth, node)
|
||||
} else if (isMinMech(node)) {
|
||||
return ruleDependenciesOfMinMech(depth, node)
|
||||
} else if (isComposantesMech(node)) {
|
||||
return ruleDependenciesOfComposantesMech(depth, node)
|
||||
} else if (isUneConditionsMech(node)) {
|
||||
return ruleDependenciesOfUneConditionsMech(depth, node)
|
||||
} else if (isToutesConditionsMech(node)) {
|
||||
return ruleDependenciesOfToutesConditionsMech(depth, node)
|
||||
} else if (isSyncMech(node)) {
|
||||
return ruleDependenciesOfSyncMech(depth, node)
|
||||
} else if (isGrilleMech(node)) {
|
||||
return ruleDependenciesOfGrilleMech(depth, node)
|
||||
} else if (isTauxProgMech(node)) {
|
||||
return ruleDependenciesOfTauxProgMech(depth, node)
|
||||
} else if (isDureeMech(node)) {
|
||||
return ruleDependenciesOfDureeMech(depth, node)
|
||||
}
|
||||
throw new Error(
|
||||
`This node doesn't have a visitor method defined: ${JSON.stringify(
|
||||
node,
|
||||
null,
|
||||
4
|
||||
)}`
|
||||
)
|
||||
|
||||
if (node.avec) {
|
||||
// [XXX] - How come we meet this? Souldn't `mecanismRecalcul` (in `mecanisms.js`) build a `Recalcul` type node?
|
||||
console.error(
|
||||
`Visited a non-parsed recalcul node, to investigate: règle ${node.règle}`
|
||||
)
|
||||
} else {
|
||||
debugger
|
||||
throw new Error(
|
||||
`This node doesn't have a visitor method defined: ${JSON.stringify(
|
||||
node,
|
||||
null,
|
||||
4
|
||||
)}`
|
||||
)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
function ruleDependenciesOfRule<Name extends string>(
|
||||
|
@ -334,15 +946,16 @@ function ruleDependenciesOfRule<Name extends string>(
|
|||
logVisit(depth, 'rule', rule.dottedName as string)
|
||||
if (rule.formule) {
|
||||
const formuleNode: FormuleNode<Name> = rule.formule.explanation
|
||||
// This is for comfort, as the responsibility over structure isn't owned by this piece of code:
|
||||
if (!isFormuleNode(formuleNode)) {
|
||||
debugger
|
||||
// throw Error(
|
||||
// `This rule's formule is not of a known type: ${rule.dottedName}`
|
||||
// )
|
||||
}
|
||||
// // This is for comfort, as the responsibility over structure isn't owned by this piece of code:
|
||||
// if (!isFormuleNode(formuleNode)) {
|
||||
// debugger
|
||||
// // throw Error(
|
||||
// // `This rule's formule is not of a known type: ${rule.dottedName}`
|
||||
// // )
|
||||
// }
|
||||
return ruleDependenciesOfNode(depth + 1, formuleNode)
|
||||
} else return [rule.dottedName]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export function buildRulesDependencies<Name extends string>(
|
||||
|
@ -355,12 +968,11 @@ export function buildRulesDependencies<Name extends string>(
|
|||
const pairs: Array<[Name, RuleNode<Name>]> = stringPairs as Array<
|
||||
[Name, RuleNode<Name>]
|
||||
>
|
||||
const pairsResults: Array<Array<Name>> = R.map(
|
||||
([_, ruleNode]: [Name, RuleNode<Name>]): Array<Name> =>
|
||||
ruleDependenciesOfRule<Name>(0, ruleNode),
|
||||
pairs
|
||||
)
|
||||
console.log(pairsResults)
|
||||
// const pairsResults: Array<Array<Name>> = R.map(
|
||||
// ([_, ruleNode]: [Name, RuleNode<Name>]): Array<Name> =>
|
||||
// ruleDependenciesOfRule<Name>(0, ruleNode),
|
||||
// pairs
|
||||
// )
|
||||
|
||||
return R.map(
|
||||
([dottedName, ruleNode]: [Name, RuleNode<Name>]): [Name, Array<Name>] => [
|
||||
|
|
|
@ -12,7 +12,7 @@ type MecanismRoundProps = {
|
|||
explanation: ArrondiExplanation
|
||||
}
|
||||
|
||||
type ArrondiExplanation = {
|
||||
export type ArrondiExplanation = {
|
||||
value: EvaluatedNode<string, number>
|
||||
decimals: EvaluatedNode<string, number>
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue