@gefyra/diffyr6-cli 1.1.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/default-rules.json +3 -3
- package/config/searchparameters-r4-not-in-r6.json +1203 -0
- package/package.json +1 -1
- package/src/compare-searchparameters.js +328 -0
- package/src/config.js +23 -3
- package/src/index.js +137 -20
- package/src/rules-engine.js +111 -1
package/src/rules-engine.js
CHANGED
|
@@ -565,7 +565,7 @@ function evaluateCondition(condition, row, lookup) {
|
|
|
565
565
|
}
|
|
566
566
|
const cellValue = row.values[columnAlias] || '';
|
|
567
567
|
const expected = resolveExpectedValue(condition, row, lookup);
|
|
568
|
-
const operator = (condition.operator || '')
|
|
568
|
+
const operator = normalizeOperator(condition.operator || '');
|
|
569
569
|
const caseSensitive = Boolean(condition.caseSensitive);
|
|
570
570
|
if (operator === 'equals') {
|
|
571
571
|
return compareEquals(cellValue, expected, caseSensitive);
|
|
@@ -576,9 +576,23 @@ function evaluateCondition(condition, row, lookup) {
|
|
|
576
576
|
if (operator === 'contains') {
|
|
577
577
|
return compareContains(cellValue, expected, caseSensitive);
|
|
578
578
|
}
|
|
579
|
+
if (operator === 'typesubsetof') {
|
|
580
|
+
return typeListIsSubset(cellValue, expected);
|
|
581
|
+
}
|
|
582
|
+
if (operator === '!typesubsetof') {
|
|
583
|
+
return !typeListIsSubset(cellValue, expected);
|
|
584
|
+
}
|
|
579
585
|
return false;
|
|
580
586
|
}
|
|
581
587
|
|
|
588
|
+
function normalizeOperator(operator) {
|
|
589
|
+
const value = String(operator).trim().toLowerCase();
|
|
590
|
+
if (value === 'nottypesubsetof' || value === 'not-typesubsetof') {
|
|
591
|
+
return '!typesubsetof';
|
|
592
|
+
}
|
|
593
|
+
return value;
|
|
594
|
+
}
|
|
595
|
+
|
|
582
596
|
function resolveExpectedValue(condition, row, lookup) {
|
|
583
597
|
if (condition.valueColumn) {
|
|
584
598
|
const alias = resolveColumnAlias(condition.valueColumn, lookup);
|
|
@@ -611,6 +625,102 @@ function compareContains(left, right, caseSensitive) {
|
|
|
611
625
|
return String(left).toLowerCase().includes(String(right).toLowerCase());
|
|
612
626
|
}
|
|
613
627
|
|
|
628
|
+
function normalizeTypeName(name) {
|
|
629
|
+
return String(name)
|
|
630
|
+
.trim()
|
|
631
|
+
.replace(/[- ]?r[46]$/i, '')
|
|
632
|
+
.toLowerCase();
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function normalizeReferenceGroup(referenceStr) {
|
|
636
|
+
const match = String(referenceStr)
|
|
637
|
+
.trim()
|
|
638
|
+
.match(/^reference\s*\((.*)\)$/i);
|
|
639
|
+
if (!match) {
|
|
640
|
+
return `reference:${normalizeTypeName(referenceStr)}`;
|
|
641
|
+
}
|
|
642
|
+
const normalizedTargets = match[1]
|
|
643
|
+
.split('|')
|
|
644
|
+
.map((token) => normalizeTypeName(token))
|
|
645
|
+
.filter(Boolean)
|
|
646
|
+
.sort();
|
|
647
|
+
return `reference:${normalizedTargets.join('|')}`;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function parseTypeList(typeStr) {
|
|
651
|
+
const types = new Set();
|
|
652
|
+
const references = [];
|
|
653
|
+
let current = '';
|
|
654
|
+
let depth = 0;
|
|
655
|
+
|
|
656
|
+
const pushCurrent = () => {
|
|
657
|
+
const token = current.trim();
|
|
658
|
+
current = '';
|
|
659
|
+
if (!token) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
if (token.toLowerCase().startsWith('reference')) {
|
|
663
|
+
references.push(parseReferenceTargets(token));
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
const normalized = normalizeTypeName(token);
|
|
667
|
+
if (normalized) {
|
|
668
|
+
types.add(normalized);
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
for (const char of String(typeStr)) {
|
|
673
|
+
if (char === '(') {
|
|
674
|
+
depth += 1;
|
|
675
|
+
current += char;
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (char === ')') {
|
|
679
|
+
depth = Math.max(0, depth - 1);
|
|
680
|
+
current += char;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (char === ',' && depth === 0) {
|
|
684
|
+
pushCurrent();
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
current += char;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
pushCurrent();
|
|
691
|
+
return { types, references };
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function parseReferenceTargets(referenceStr) {
|
|
695
|
+
const normalized = normalizeReferenceGroup(referenceStr);
|
|
696
|
+
const [, targetList = ''] = normalized.split(':');
|
|
697
|
+
return new Set(targetList.split('|').filter(Boolean));
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
function typeListIsSubset(leftStr, rightStr) {
|
|
701
|
+
const leftTypes = parseTypeList(leftStr);
|
|
702
|
+
const rightTypes = parseTypeList(rightStr);
|
|
703
|
+
for (const type of leftTypes.types) {
|
|
704
|
+
if (!rightTypes.types.has(type)) {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
for (const leftReference of leftTypes.references) {
|
|
709
|
+
const hasSuperset = rightTypes.references.some((rightReference) => {
|
|
710
|
+
for (const target of leftReference) {
|
|
711
|
+
if (!rightReference.has(target)) {
|
|
712
|
+
return false;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return true;
|
|
716
|
+
});
|
|
717
|
+
if (!hasSuperset) {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
723
|
+
|
|
614
724
|
function renderTemplate(template, variables) {
|
|
615
725
|
const rendered = template.replace(/{{\s*([^}]+)\s*}}/g, (_, key) => {
|
|
616
726
|
const resolved = resolveVariableValue(key.trim(), variables);
|