From c45b78c2e54d9ce16c82e301e606f7332fa0c516 Mon Sep 17 00:00:00 2001 From: Alexandre Hajjar Date: Tue, 21 Apr 2020 14:23:58 +0200 Subject: [PATCH] =?UTF-8?q?WIP=20=E2=9A=99=EF=B8=8F=20Detect=20cycles:=20s?= =?UTF-8?q?olifidy=20types=20and=20guards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mon-entreprise/test/cycles.test.js | 1 + publicodes/source/cyclesLib.ts | 104 +++++++++++++++++++---------- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/mon-entreprise/test/cycles.test.js b/mon-entreprise/test/cycles.test.js index 45219a95d..8d73422fe 100644 --- a/mon-entreprise/test/cycles.test.js +++ b/mon-entreprise/test/cycles.test.js @@ -3,6 +3,7 @@ import rules from 'Rules' describe('Graph', () => { it('should get a graph', () => { + debugger // Keep this for allowing deactivating other debugger statements via the Chrome inspector let parsedRules = parseRules(rules) let ruleDependencies = buildRulesDependencies(parsedRules) console.log(ruleDependencies) diff --git a/publicodes/source/cyclesLib.ts b/publicodes/source/cyclesLib.ts index 555bbbd2b..a8cfbf484 100644 --- a/publicodes/source/cyclesLib.ts +++ b/publicodes/source/cyclesLib.ts @@ -4,7 +4,7 @@ */ import { chain, partial } from 'ramda' -import { ParsedRules } from './types' +import { ParsedRule, ParsedRules } from './types' // type GraphNode = { // name: string @@ -12,57 +12,90 @@ import { ParsedRules } from './types' // } type DottedName = string -type ASTNode = any +type ASTNode = Record -type RuleNode = any // extends ASTNode +type RuleNode = /* ASTNode & */ ParsedRule -type Value = any // extends ASTNode - -type Operation = any // extends ASTNode - -type Reference = ASTNode & { - category: 'reference' - dottedName: DottedName +type Value = ASTNode & { + nodeValue: any + constant: true } - -type Possibilities = any // extends ASTNode - -type Recalcul = ASTNode & { - règle: DottedName -} // [XXX] - faire la meme pour les autres - -type Mechanism = any // extends ASTNode - -type FormuleNode = Value | Operation | Possibilities | Recalcul | Mechanism - -type EncadrementMech = any // extends Mechanism - -type SommeMech = any // extends Mechanism - export function isValue(node): node is Value { - return (node as Value).nodeValue !== undefined + return ( + (node as Value).nodeValue !== undefined && (node as Value).constant === true + ) } +type Operation = ASTNode & { + operationType: 'comparison' | 'calculation' +} export function isOperation(node): node is Operation { - return (node as Operation).operationType !== undefined + return ['comparison', 'calculation'].includes( + (node as Operation).operationType + ) } +type Possibilities = ASTNode & { + possibilités: Array + 'choix obligatoire'?: 'oui' | 'non' // [XXX] - This should already be a defined type. + 'une possibilité': 'oui' | 'non' +} +export function isPossibilities(node): node is Possibilities { + const possibilities = node as Possibilities + return ( + possibilities.possibilités instanceof Array && + possibilities.possibilités.every(it => typeof it === 'string') && + ['oui', 'non'].includes(possibilities['choix obligatoire']) && + ['oui', 'non'].includes(possibilities['une possibilité']) + ) +} + +type Reference = Omit & { + // [XXX] - a priori non pour le omit, il n'y a pas du tout autant de choses que dans RuleNode à l'intérieur d'une reference + category: 'reference' + partialReference: DottedName +} export function isReference(node): node is Reference { return (node as Reference).category === 'reference' } -export function isPossibilities(node): node is Possibilities { - return (node as Possibilities).possibilités !== undefined +type Recalcul = ASTNode & { + explanation: { + recalcul: Reference + amendedSituation: Record + } } - export function isRecalcul(node): node is Recalcul { - return (node as Recalcul).règle !== undefined // [XXX] - A VERIF + const recalcul = node as Recalcul + return ( + typeof recalcul.explanation === 'object' && + isReference(recalcul.explanation.recalcul as ASTNode) && + typeof recalcul.explanation.amendedSituation === 'object' && + Object.entries(recalcul.explanation.amendedSituation).every(([_, v]) => + isReference(v as ASTNode) + ) + ) } +type Mechanism = ASTNode & { + category: 'mecanism' +} export function isMechanism(node): node is Mechanism { return (node as Mechanism).category === 'mecanism' } +type FormuleNode = + | Value + | Operation + | Possibilities + | Reference + | Recalcul + | Mechanism + +type EncadrementMech = any // extends Mechanism + +type SommeMech = any // extends Mechanism + export function isFormuleNode(node): node is FormuleNode { return ( isValue(node as Value) || @@ -164,7 +197,6 @@ export function ruleDependenciesOfNode( } else if (isMechanism(node)) { return ruleDependenciesOfMechanism(depth, node as Mechanism) } - debugger return [] // [XXX] } @@ -172,15 +204,15 @@ function ruleDependenciesOfRule( depth: number, rule: RuleNode ): Array { - logVisit(depth, 'rule', rule.dottedName) + logVisit(depth, 'rule', rule.dottedName as string) if (rule.formule) { const formuleNode: FormuleNode = 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}` - ) + // throw Error( + // `This rule's formule is not of a known type: ${rule.dottedName}` + // ) } return ruleDependenciesOfNode(depth + 1, formuleNode) } else return [rule.dottedName]