Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
core_analytics_quality.checksEngine.pure Maven / Gradle / Ivy
import meta::analytics::quality::model::*;
import meta::analytics::quality::model::domain::*;
import meta::relational::tests::*;
import meta::pure::runtime::*;
Enum meta::analytics::quality::model::Severity
{
High, Medium, Low
}
Enum meta::analytics::quality::model::Category
{
Modelling, Correctness, Quality, Testing
}
Class meta::analytics::quality::model::Rule
{
id : String[1];
func: FunctionDefinition<{T[1]->Any[*]}>[1];
severity : Severity[1];
category : Category[1];
description: String[1];
hasSkipTestsFlag : Boolean[1];
}
Profile meta::analytics::quality::model::rule
{
stereotypes: [skipTests];
tags: [rule, severity, category, description, ignore];
}
Class meta::analytics::quality::model::CheckResult
{
isValid: Boolean[1];
message: String[1];
}
Class meta::analytics::quality::model::ViolationInstance
{
source : T[1];
rule : Rule[1];
sourceInfo() { $this.source->sourceInformation()}: SourceInformation[0..1] ;
detail :
CheckResult[1];
}
Class meta::analytics::quality::model::Rankings
{
severity() { [pair(Severity.High, 1), pair(Severity.Medium, 2),pair(Severity.Low, 3)]}: Pair[*];
severity(severity :Severity[1]) { $this.severity()->filter(p|$p.first == $severity)->toOne().second} : Integer[1];
}
function <> meta::analytics::quality::model::domain::apply(rule:Rule[1],pe:AbstractProperty[1]):Any[*]
{
if($rule->skipInTests($pe), |[], |$rule.func->eval($pe))
}
function {doc.doc = 'Run quality checks for class properties'}
meta::analytics::quality::model::domain::runClassPropertyQualityChecks(cl:Class[1],rules:Rule>[*]):ViolationInstance[*]
{
let properties = $cl->allProperties();
$properties->map(p:AbstractProperty[1] | $rules->map(rule:Rule>[1] | $rule->apply($p)->cast(@CheckResult)->violationHandler($p, $rule)));
}
function <> meta::analytics::quality::model::domain::skipInTests(rule:Rule[1],pe:Any[1]):Boolean[1]
{
if($rule.hasSkipTestsFlag ,
|
let pName = $pe->match([p:PackageableElement[1]|$p->fullPackageName('::'), p:AbstractProperty[1]|$p->fullPackageName('::')]);
let si = $pe->sourceInformation();
$pName->contains('::tests::') || $pName->contains('::test::')|| $si.source->contains('/test/') || $si.source->contains('/tests/');,
| false
);
}
function {doc.doc = 'Handles model checks violations'}
//TODO: there is a bug with generics so ViolationInstance instead of ViolationInstance
meta::analytics::quality::model::domain::violationHandler(detail:CheckResult[*],element: Any[1],rule: Rule[1]):ViolationInstance[*]
{
$detail->filter(r | !$r.isValid)->map(r | ^ViolationInstance(source=$element, rule=$rule, detail=$r));
}
function meta::analytics::quality::model::domain::createRule(ruleFunctionB: FunctionDefinition<{T[1]->Any[*]}>[1]):Rule[1]
{
let ruleFunction = $ruleFunctionB->cast(@AnnotatedElement);
let tags = $ruleFunction.taggedValues;
let rule = $ruleFunction->value4Tag('rule', rule).value->toOne();
let description = $ruleFunction->value4Tag('description', rule).value->toOne();
let severity = Severity->extractEnumValue($tags->filter(t | $t.tag == rule->tag('severity'))->map(t | $t.value)->toOne()->toString());
let category = Category->extractEnumValue($tags->filter(t | $t.tag == rule->tag('category'))->map(t | $t.value)->toOne()->toString());
let skipTestsTag = $ruleFunction->hasStereotype('skipTests',meta::analytics::quality::model::rule);
^Rule(id=$rule,func=$ruleFunctionB,severity=$severity,category=$category,description=$description,hasSkipTestsFlag=$skipTestsTag);
}
function {doc.doc='Run quality checks for all elements in a package'}
meta::analytics::quality::model::domain::runQualityChecks(elements:PackageableElement[*]):ViolationInstance[*]
{
let functionRules = functionRules();
let enumerationRules = enumerationRules();
let associationRules = associationRules();
let classRules = classRules();
let propertyRules = propertyRules();
let allElements = $elements->filter(e | $e->instanceOf(Package))->cast(@Package)->map(p | $p->getAllPackageElements(true))->concatenate($elements)->removeDuplicates();
let funcViolations = $allElements->filter(x|$x->instanceOf(FunctionDefinition))->cast(@FunctionDefinition)->runQualityChecksForFunctions($functionRules);
let classes = $allElements->filter(x|$x->instanceOf(Class))->cast(@Class);
let associations = $allElements->filter(x|$x->instanceOf(Association));
let classViolations = $classes->runQualityChecksForClass($classRules, $propertyRules)->concatenate($classes.qualifiedProperties->runQualityChecksForFunctions($functionRules));
let enumerationViolations = $allElements->filter(x|$x->instanceOf(Enumeration))->cast(@Enumeration)->runQualityChecksForEnumerations($enumerationRules);
let associationViolations = $allElements->filter(x|$x->instanceOf(Association))->cast(@Association)->runQualityChecksForAssociations($associationRules);
$funcViolations->concatenate($classViolations)->concatenate($enumerationViolations)->concatenate($associationViolations);
}
function {doc.doc = 'Run Quality checks for functions'}
meta::analytics::quality::model::domain::runQualityChecksForFunctions(fns:FunctionDefinition[*], rules : Rule>>[*]):ViolationInstance[*]
{
if($fns->isEmpty()
,|[]
,|$rules->map(rule|
let ruleFunction=$rule.func->cast(@FunctionDefinition<{List>[1]->Pair[*]}>);//todo this is a hack for compile mode
let filtersFns = $fns->filter(f|!$rule->skipInTests($f));
let results = $ruleFunction->eval(^List>(values=$filtersFns));
$results->map(p|
[]->concatenate($p.second)->violationHandler($p.first,$rule);
);
);
);
}
function {doc.doc = 'Run quality checks for classes, their properties and abstract functions'}
meta::analytics::quality::model::domain::runQualityChecksForClass(cls:Class[*], classRules:Rule>[*], propRules:Rule>[*]):ViolationInstance[*]
{
$cls->map(cl| $classRules->map(rule:Rule>[1] | $rule->apply($cl)->cast(@CheckResult)->violationHandler($cl, $rule))
->concatenate($cl->meta::analytics::quality::model::domain::runClassPropertyQualityChecks($propRules)));
}
function {doc.doc = 'Run quality checks for enums'}
meta::analytics::quality::model::domain::runQualityChecksForEnumerations(e:Enumeration[*], enumerationRules:Rule>[*]):ViolationInstance[*]
{
$e->map(e | $enumerationRules->map(rule:Rule>[1] | $rule->apply($e)->cast(@CheckResult)->violationHandler($e, $rule)));
}
function {doc.doc = 'Run quality checks for associations'}
meta::analytics::quality::model::domain::runQualityChecksForAssociations(e:Association[*], associationRules:Rule[*]):ViolationInstance[*]
{
$e->map(e | $associationRules->map(rule:Rule[1] | $rule->apply($e)->cast(@CheckResult)->violationHandler($e, $rule)));
}
function <> meta::analytics::quality::model::domain::apply(rule:Rule[1],pe:PackageableElement[1]):Any[*]
{
if($rule->skipInTests($pe), |[], |$rule.func->eval($pe))
}
function meta::analytics::quality::model::domain::runRules(pkg:PackageableElement[*]) : ViolationInstance[*]
{
let severity = newMap(^Rankings().severity);
$pkg->removeDuplicates()
->runQualityChecks()
->removeDuplicates()
->cast(@ViolationInstance)
->filter(bug|!$bug.detail.isValid)
->filterInstancesToIgnore()
->sortBy(b | $severity->get($b.rule.severity)->toOne());
}
function meta::analytics::quality::model::domain::filterInstancesToIgnore(i:ViolationInstance[*]) : ViolationInstance[*]
{
$i->filter(v| let ignoreTag = $v.source->match([e:ElementWithTaggedValues[1]| $e->value4Tag('ignore', rule).value,
fe:FunctionExpression[1]| $fe.usageContext->match(
[es:ExpressionSequenceValueSpecificationContext[1]| if($es.functionDefinition->instanceOf(AnnotatedElement),|$es.functionDefinition->cast(@AnnotatedElement)->value4Tag('ignore', rule).value, |[]);,
a: ValueSpecificationContext[1]|''
]);,
a:Any[1]| println($a);'';]);
if( $ignoreTag->isEmpty()
,| true
,| let values = $ignoreTag->toOne()->split(',');
!$v.rule.id->in($values);
);
);
}
function meta::analytics::quality::model::domain::runChecksAsHtml(pkgs:PackageableElement[*],elements:String[*],service:Boolean[1]):String[1]
{
let bugs = meta::analytics::quality::model::domain::runRules($pkgs);
let bugDetailsTable = [
'',
'
',
'',
'Severity ',
'Category ',
'Rule ',
'Message ',
'Element ',
' '
]->concatenate(
$bugs->map({bug|
let pe = $bug.source->findPackagableElement();
let peName = $bug.source->match([p:PackageableElement[1]| $p->fullPackageName('::'),a:Any[1]|$pe->fullPackageName('::') ]) ;
[
'',
('' + $bug.rule.severity->makeString() + ' '),
('' + $bug.rule.category->makeString() + ' '),
('' + $bug.rule.description->makeString() + ' '),
('' + $bug.detail.message->makeString() + ' '),
if($service
,|('' + $pe->cast(@PackageableElement)->fullPackageName('::') + ' ')
,|('' + 'toOne().source + '\",' + $bug.sourceInfo->toOne().startLine->toString() + ',' + $bug.sourceInfo->toOne().startColumn->toString() + ',false); return false;\'>'
+ $peName+ ' '+ ' ')
),
' '
];
})
)->concatenate([
'
',
'
'
]);
let packagesInfo = [
'',
'
',
'Inspected elements: '
]
->concatenate($elements->map(e | $e + ' ')->sort()->joinStrings(''))
->concatenate(
['
'])
;
let rulesInfo = [
'',
'
',
'',
'Rule ',
'Severity ',
'Category ',
'Description ',
'Rule code ',
' '
]
->concatenate(classRules()->map(r | $r->createRuleHTMLRow('Classes',$service)))
->concatenate(propertyRules()->map(r | $r->createRuleHTMLRow('Properties',$service)))
->concatenate(functionRules()->map(r | $r->createRuleHTMLRow('Functions',$service)))
->concatenate(enumerationRules()->map(r | $r->createRuleHTMLRow('Enumerations',$service)))
->concatenate(associationRules()->map(r | $r->createRuleHTMLRow('Associations',$service)))
->concatenate([
'
',
'
'
]);
let stats = ''+ $bugs->meta::analytics::quality::model::domain::buildStatsTable('Rule')+'
';
let scripts = if($service,|
''+
''+
' '
,|'');
let page = [
'',
'PURE Quality Checks ',
'',
'',
$scripts,
'',
'',
'',
'',
'
']
->concatenate($stats)
->concatenate($packagesInfo)
->concatenate($bugDetailsTable)
->concatenate($rulesInfo)
->concatenate
([
'',
'',
''
]) ->joinStrings('\n');
$page;
}
function <
> meta::analytics::quality::model::domain::createRuleHTMLRow(r:Rule[1],type:String[1],service:Boolean[1]):String[1]
{
let pe = $r.func;
let si= $pe->sourceInformation()->toOne();
''+$type +' '+$r.severity->toString() + ' ' + $r.category->toString() + ' ' + $r.description +' ' +
if($service
,|('' + $pe->cast(@PackageableElement)->fullPackageName('::') + ' ')
,|('' + 'toString() + ',' + $si.startColumn->toString() + ',false); return false;\'>'
+ $pe->cast(@PackageableElement)->fullPackageName('::') + ' '+ ' ')
);
}
function <> meta::analytics::quality::model::domain::buildStatsTable(items : ViolationInstance[*], name : String[1]) : String[1]
{
let severity = newMap(^Rankings().severity);
let pairs = $items->map(e| ^Pair,Integer>(first=$e.rule,second=1));
let keys = $pairs.first->distinct()->cast(@Rule);
let stats = $keys->map(k|let p=^Pair(first=$severity->get($k.severity)->toOne(),second=$pairs->filter(p|$p.first == $k).second->sum());
^Pair,Pair>(first=$k, second = $p);)
->sort({a,b| $a.second.first->compare($b.second.first) + (-1* $a.second.second->compare($b.second.second)) }); // sort by severity then count
let rows =$stats
->map({p|
let percent = (($p.second.second / $items->size()) * 100);
[
'',
('' + $p.first.id->makeString() + ' '),
('' + $p.first.severity->makeString() + ' '),
('' + $p.second.second->makeString() + ' '),
('' + if ($percent > 0.1, | format('%.2f', [$percent]), | 'n/a') + '% '),
' '
];
})->cast(@String);
let statsTable = [
'']
->concatenate(['Total ',$items->size()->toString(),' Violation Instances '])
->concatenate([('' + $name + ' '),
'Severity ',
'Count ',
'% ',
' '])
->concatenate($rows)
->concatenate(['
']);
$statsTable->joinStrings('');
}
function {service.url='/quality/reports/{element}', service.contentType='text/html'}
meta::analytics::quality::model::domain::findBugsReports(element : String[1]) : String[1]
{
let pe = $element->pathToElement();
[$pe]->meta::analytics::quality::model::domain::runChecksAsHtml($pe->fullPackageName('::'),true);
}