Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(compilation): import rules in custom namespace #18

Merged
merged 3 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions source/compilation/getModelFromSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ const IMPORT_KEYWORD = 'importer!'
* ```yaml
* importer!:
* depuis:
* nom: 'my-external-package'
* source: 'my-external-package.model.yaml'
* nom: my-external-package
* source: my-external-package.model.yaml
* dans: root
* les règles:
* - règle 1
* - règle 2:
* question: 'Quelle est la valeur de la règle 2 ?'
* question: Quelle est la valeur de la règle 2 ?
*/
export type ImportMacro = {
depuis: {
Expand All @@ -37,6 +38,8 @@ export type ImportMacro = {
// The URL of the package, used for the documentation.
url?: string
}
// The namespace where to import the rules.
dans?: string
// List of rules to import from the package.
// They could be specified by their name, or by the name and the list of
// properties to override or add.
Expand Down Expand Up @@ -221,8 +224,8 @@ function appearsMoreThanOnce(
)
}

function accIncludes(acc: [string, Rule][], ruleName: RuleName): boolean {
return acc.find(([accRuleName, _]) => accRuleName === ruleName) !== undefined
function accFind(acc: [string, Rule][], ruleName: RuleName): [string, Rule] {
return acc.find(([accRuleName, _]) => accRuleName === ruleName)
}

/**
Expand All @@ -248,7 +251,7 @@ function resolveImports(
`La règle '${ruleName}' est définie deux fois dans ${importMacro.depuis.nom}`,
)
}
if (accIncludes(acc, ruleName)) {
if (accFind(acc, ruleName)) {
return acc
}

Expand All @@ -267,7 +270,7 @@ function resolveImports(
rule,
)
return [
ruleName,
importMacro.dans ? `${importMacro.dans} . ${ruleName}` : ruleName,
removeRawNodeNom(ruleWithUpdatedDescription, ruleName),
]
}
Expand All @@ -278,17 +281,26 @@ function resolveImports(
const ruleDeps = getDependencies(engine, rule)
.filter(([ruleDepName, _]) => {
// Avoid to overwrite the updatedRawNode
return !accIncludes(acc, ruleDepName)
return !accFind(acc, ruleDepName)
})
.map(([ruleName, ruleNode]) => {
return getUpdatedRule(ruleName, ruleNode)
})
acc.push(...ruleDeps)
})
} else {
if (accIncludes(acc, name)) {
let doubleDefinition = accFind(acc, name)
if (doubleDefinition) {
throw new Error(
`[${basename(filePath)}] La règle '${name}' est déjà définie`,
`[${basename(filePath)}] La règle '${name}' est déjà définie

Essaie de remplacer :

${yaml.stringify(doubleDefinition[1], { indent: 2 })}

Avec :

${yaml.stringify(value, { indent: 2 })}`,
)
}
acc.push([name, value])
Expand Down
1 change: 1 addition & 0 deletions source/compilation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ importer!:
nom: <npm_package_name>
source: <path_to_the_model_file> (optional)
url: <url_to_the_package_documentation> (optional)
dans: <namespace> (optional)
les règles:
- <rule_name_from_the_npm_package>
- <rule_name_from_the_npm_package>:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
importer!:
depuis:
nom: my-external-package
source: ./my-external-package.model.json
dans: pkg
les règles:
- complex
11 changes: 11 additions & 0 deletions test/compilation/data/rules-doublon-with-namespace.publicodes
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
importer!:
depuis:
nom: 'my-external-package'
source: './my-external-package.model.json'
dans: pkg
les règles:
- root . b

pkg . root:
pkg . root . c:
titre: Conflicting rule with dependency of 'root . b' in my-external-package imported in 'pkg'
49 changes: 49 additions & 0 deletions test/compilation/getModelFromSource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,53 @@ Ajout d'une description`,
getModelFromSource(join(testDataDir, baseName))
}).toThrow(`[${baseName}] La règle 'root . c' est déjà définie`)
})

it('should import a rule from a package with all dependencies from a complex formula in a custom namespace', () => {
expect(
getModelFromSource(
join(testDataDir, 'complex-deps-with-namespace-import.publicodes'),
),
).toEqual({
'pkg . complex': {
formule: {
somme: ['d', 'root'],
},
description: updatedDescription,
},
'pkg . root': {
formule: 'a * b',
description: updatedDescription,
},
'pkg . root . a': {
formule: 10,
description: updatedDescription,
},
'pkg . root . b': {
formule: 'root . c * 2',
description: updatedDescription,
},
'pkg . root . c': {
formule: 20,
description: updatedDescription,
},
'pkg . root 2': {
formule: 20,
résumé: 'Résumé root 2',
description: updatedDescription,
},
'pkg . d': {
formule: {
variations: [{ si: 'root 2 > 10', alors: 10 }, { sinon: 'root 2' }],
},
description: updatedDescription,
},
})
})

it('should throw an error if there is conflict between an imported rule and a base rule with a custom namespace', () => {
const baseName = 'rules-doublon-with-namespace.publicodes'
expect(() => {
getModelFromSource(join(testDataDir, baseName))
}).toThrow(`[${baseName}] La règle 'pkg . root . c' est déjà définie`)
})
})
Loading