diff --git a/platform/core/src/services/HangingProtocolService/lib/validator.js b/platform/core/src/services/HangingProtocolService/lib/validator.js
index 498ae3201..3be5b16de 100644
--- a/platform/core/src/services/HangingProtocolService/lib/validator.js
+++ b/platform/core/src/services/HangingProtocolService/lib/validator.js
@@ -1,69 +1,240 @@
import validate from 'validate.js';
+/**
+ * check if the value is strictly equal to options
+ *
+ * @example
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'abc' (Fail)
+ * = ['abc'] (Fail)
+ * = ['abc', 'def', 'GHI'] (Valid)
+ * = ['abc', 'GHI', 'def'] (Fail)
+ * = ['abc', 'def'] (Fail)
+ *
+ * value = 'Attenuation Corrected'
+ * testValue = 'Attenuation Corrected' (Valid)
+ * testValue = 'Attenuation' (Fail)
+ *
+ * value = ['Attenuation Corrected']
+ * testValue = ['Attenuation Corrected'] (Valid)
+ * = 'Attenuation Corrected' (Valid)
+ * = 'Attenuation' (Fail)
+ *
+ * */
+validate.validators.equals = function(value, options, key) {
+ const testValue = getTestValue(options);
+ const dicomArrayValue = dicomTagToArray(value);
-validate.validators.equals = function(value, options, key, attributes) {
- const testValue = options?.value ?? options;
- if (value !== testValue) {
- return key + 'must equal ' + testValue;
+ // If options is an array, then we need to validate each element in the array
+ if (Array.isArray(testValue)) {
+ // If the array has only one element, then we need to compare the value to that element
+ if (testValue.length !== dicomArrayValue.length) {
+ return `${key} must be an array of length ${testValue.length}`;
+ } else {
+ for (let i = 0; i < testValue.length; i++) {
+ if (testValue[i] !== dicomArrayValue[i]) {
+ return `${key} ${testValue[i]} must equal ${dicomArrayValue[i]}`;
+ }
+ }
+ }
+ } else if (testValue !== dicomArrayValue[0]) {
+ return `${key} must equal ${testValue}`;
}
};
-
+/**
+ * check if the value is not equal to options
+ *
+ * @example
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'abc' (Valid)
+ * = ['abc'] (Valid)
+ * = ['abc', 'def', 'GHI'] (Fail)
+ * = ['abc', 'GHI', 'def'] (Valid)
+ * = ['abc', 'def'] (Valid)
+ *
+ * value = 'Attenuation Corrected'
+ * = 'Attenuation Corrected' (Fail)
+ * = 'Attenuation' (Valid)
+ *
+ * value = ['Attenuation Corrected']
+ * testValue = ['Attenuation Corrected'] (Fail)
+ * = 'Attenuation Corrected' (Fail)
+ * = 'Attenuation' (Fail)
+ * */
validate.validators.doesNotEqual = function(value, options, key) {
- const testValue = options?.value ?? options;
- if (value === testValue) {
- return key + 'cannot equal ' + testValue;
+ const testValue = getTestValue(options);
+ const dicomArrayValue = dicomTagToArray(value);
+
+ if (Array.isArray(testValue)) {
+ if (testValue.length === dicomArrayValue.length) {
+ let score = 0;
+ testValue.forEach((x, i) => {
+ if (x === dicomArrayValue[i]) {
+ score++;
+ }
+ });
+ if (score === testValue.length) {
+ return `${key} must not equal to ${testValue}`;
+ }
+ }
+ } else if (testValue === dicomArrayValue[0]) {
+ console.debug(dicomArrayValue, testValue);
+ return `${key} must not equal to ${testValue}`;
}
};
+/**
+ * Check if a value includes one or more specified options.
+ *
+ * @example
+ * value = ['abc', 'def', 'GHI']
+ * testValue = ‘abc’ (Fail)
+ * = ‘dog’ (Fail)
+ * = [‘abc’] (Valid)
+ * = [‘att’, ‘abc’] (Valid)
+ * = ['abc', 'def', 'dog'] (Valid)
+ * = ['cat', 'dog'] (Fail)
+ *
+ * value = ['Attenuation Corrected']
+ * testValue = 'Attenuation Corrected' (Fail)
+ * = ['Attenuation Corrected', 'Corrected'] (Valid)
+ * = ['Attenuation', 'Corrected'] (Fail)
+ *
+ * value = 'Attenuation Corrected'
+ * testValue = ['Attenuation Corrected', 'Corrected'] (Valid)
+ * = ['Attenuation', 'Corrected'] (Fail)
+ * */
+validate.validators.includes = function(value, options, key) {
+ const testValue = getTestValue(options);
+ const dicomArrayValue = dicomTagToArray(value);
+
+ if (Array.isArray(testValue)) {
+ const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
+ if (includedValues.length === 0) {
+ return `${key} must include at least one of the following values: ${testValue.join(
+ ', '
+ )}`;
+ }
+ } else return `${key} ${testValue} must be an array`;
+ // else if (!value.includes(testValue)) {
+ // return `${key} ${value} must include ${testValue}`;
+ // }
+};
+/**
+ * Check if a value does not include one or more specified options.
+ *
+ * @example
+ * value = ['abc', 'def', 'GHI']
+ * testValue = ['Corr'] (Valid)
+ * = 'abc' (Fail)
+ * = ['abc'] (Fail)
+ * = [‘att’, ‘cor’] (Valid)
+ * = ['abc', 'def', 'dog'] (Fail)
+ *
+ * value = ['Attenuation Corrected']
+ * testValue = 'Attenuation Corrected' (Fail)
+ * = ['Attenuation Corrected', 'Corrected'] (Fail)
+ * = ['Attenuation', 'Corrected'] (Valid)
+ *
+ * value = 'Attenuation Corrected'
+ * testValue = ['Attenuation Corrected', 'Corrected'] (Fail)
+ * = ['Attenuation', 'Corrected'] (Valid)
+ * */
+validate.validators.doesNotInclude = function(value, options, key) {
+ const testValue = getTestValue(options);
+ const dicomArrayValue = dicomTagToArray(value);
+
+ // if (!Array.isArray(value) || value.length === 1) {
+ // return `${key} is not allowed as a single value`;
+ // }
+ if (Array.isArray(testValue)) {
+ const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
+ if (includedValues.length > 0) {
+ return `${key} must not include the following value: ${includedValues}`;
+ }
+ } else return `${key} ${testValue} must be an array`;
+};
// Ignore case contains.
// options testValue MUST be in lower case already, otherwise it won't match
-validate.validators.containsI = function (value, options, key) {
- const testValue = options?.value ?? options;
+/**
+ * @example
+ * value = 'Attenuation Corrected'
+ * testValue = ‘Corr’ (Valid)
+ * = ‘corr’ (Valid)
+ * = [‘att’, ‘cor’] (Valid)
+ * = [‘Att’, ‘Wall’] (Valid)
+ * = [‘cat’, ‘dog’] (Fail)
+ *
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'def' (Valid)
+ * = 'dog' (Fail)
+ * = ['gh', 'de'] (Valid)
+ * = ['cat', 'dog'] (Fail)
+ *
+ * */
+validate.validators.containsI = function(value, options, key) {
+ const testValue = getTestValue(options);
if (Array.isArray(value)) {
if (
- value.some(
- item => !validate.validators.containsI(item.toLowerCase(), options, key)
- )
+ value.some(
+ item => !validate.validators.containsI(item.toLowerCase(), options, key)
+ )
) {
return undefined;
}
return `No item of ${value.join(',')} contains ${JSON.stringify(
- testValue
+ testValue
)}`;
}
if (Array.isArray(testValue)) {
if (
- testValue.some(
- subTest => !validate.validators.containsI(value, subTest, key)
- )
+ testValue.some(
+ subTest =>
+ !validate.validators.containsI(value, subTest.toLowerCase(), key)
+ )
) {
return;
}
return `${key} must contain at least one of ${testValue.join(',')}`;
}
if (
- testValue &&
- value.indexOf &&
- value.toLowerCase().indexOf(testValue) === -1
+ testValue &&
+ value.indexOf &&
+ value.toLowerCase().indexOf(testValue.toLowerCase()) === -1
) {
return key + 'must contain any case of' + testValue;
}
};
-
+/**
+ * @example
+ * value = 'Attenuation Corrected'
+ * testValue = ‘Corr’ (Valid)
+ * = ‘corr’ (Fail)
+ * = [‘att’, ‘cor’] (Fail)
+ * = [‘Att’, ‘Wall’] (Valid)
+ * = [‘cat’, ‘dog’] (Fail)
+ *
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'def' (Valid)
+ * = 'dog' (Fail)
+ * = ['cat', 'de'] (Valid)
+ * = ['cat', 'dog'] (Fail)
+ *
+ * */
validate.validators.contains = function(value, options, key) {
- const testValue = options?.value ?? options;
+ const testValue = getTestValue(options);
if (Array.isArray(value)) {
if (value.some(item => !validate.validators.contains(item, options, key))) {
return undefined;
}
return `No item of ${value.join(',')} contains ${JSON.stringify(
- testValue
+ testValue
)}`;
}
if (Array.isArray(testValue)) {
if (
- testValue.some(
- subTest => !validate.validators.contains(value, subTest, key)
- )
+ testValue.some(
+ subTest => !validate.validators.contains(value, subTest, key)
+ )
) {
return;
}
@@ -73,50 +244,235 @@ validate.validators.contains = function(value, options, key) {
return key + 'must contain ' + testValue;
}
};
-
+/**
+ * @example
+ * value = 'Attenuation Corrected'
+ * testValue = ‘Corr’ (Fail)
+ * = ‘corr’ (Valid)
+ * = [‘att’, ‘cor’] (Valid)
+ * = [‘Att’, ‘Wall’] (Fail)
+ * = [‘cat’, ‘dog’] (Valid)
+ *
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'def' (Fail)
+ * = 'dog' (Valid)
+ * = ['cat', 'de'] (Fail)
+ * = ['cat', 'dog'] (Valid)
+ *
+ * */
validate.validators.doesNotContain = function(value, options, key) {
- if (options && value.indexOf && value.indexOf(options.value) !== -1) {
- return key + 'cannot contain ' + options.value;
+ const containsResult = validate.validators.contains(value, options, key);
+ if (!containsResult) {
+ return `No item of ${value} should contain ${getTestValue(options)}`;
}
};
+/**
+ * @example
+ * value = 'Attenuation Corrected'
+ * testValue = ‘Corr’ (Fail)
+ * = ‘corr’ (Fail)
+ * = [‘att’, ‘cor’] (Fail)
+ * = [‘Att’, ‘Wall’] (Fail)
+ * = [‘cat’, ‘dog’] (Valid)
+ *
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'DEF' (Fail)
+ * = 'dog' (Valid)
+ * = ['cat', 'gh'] (Fail)
+ * = ['cat', 'dog'] (Valid)
+ *
+ * */
+validate.validators.doesNotContainI = function(value, options, key) {
+ const containsResult = validate.validators.containsI(value, options, key);
+ if (!containsResult) {
+ return `No item of ${value} should not contain ${getTestValue(options)}`;
+ }
+};
+/**
+ * @example
+ * value = 'Attenuation Corrected'
+ * testValue = ‘Corr’ (Fail)
+ * = ‘Att’ (Fail)
+ * = ['cat', 'dog', 'Att'] (Valid)
+ * = [‘cat’, ‘dog’] (Fail)
+ *
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'deg' (Valid)
+ * = ['cat', 'GH'] (Valid)
+ * = ['cat', 'gh'] (Fail)
+ * = ['cat', 'dog'] (Fail)
+ *
+ * */
validate.validators.startsWith = function(value, options, key) {
- if (options && value.startsWith && !value.startsWith(options.value)) {
- return key + 'must start with ' + options.value;
+ let testValues = getTestValue(options);
+
+ if (typeof testValues === 'string') {
+ testValues = [testValues];
+ }
+
+ if (typeof value === 'string') {
+ if (!testValues.some(testValue => value.startsWith(testValue))) {
+ return key + ' must start with any of these values: ' + testValues;
+ }
+ } else if (Array.isArray(value)) {
+ let valid = false;
+ for (let i = 0; i < value.length; i++) {
+ for (let j = 0; j < testValues.length; j++) {
+ if (value[i].startsWith(testValues[j])) {
+ valid = true; // set valid flag to true if a match is found
+ break;
+ }
+ }
+ if (valid) {
+ return undefined; // break out of loop if a match is found
+ }
+ }
+
+ if (!valid) {
+ return key + ' must start with any of these values: ' + testValues; // return undefined if no match is found
+ }
+ } else {
+ return 'Value must be a string or an array';
}
};
+/**
+ * @example
+ * value = 'Attenuation Corrected'
+ * testValue = ‘TED’ (Fail)
+ * = ‘ted’ (Valid)
+ * = ['cat', 'dog', 'ted'] (Valid)
+ * = [‘cat’, ‘dog’] (Fail)
+ *
+ * value = ['abc', 'def', 'GHI']
+ * testValue = 'deg' (Valid)
+ * = ['cat', 'HI'] (Valid)
+ * = ['cat', 'hi'] (Fail)
+ * = ['cat', 'dog'] (Fail)
+ *
+ * */
validate.validators.endsWith = function(value, options, key) {
- if (options && value.endsWith && !value.endsWith(options.value)) {
- return key + 'must end with ' + options.value;
+ let testValues = getTestValue(options);
+
+ if (typeof testValues === 'string') {
+ testValues = [testValues];
+ }
+
+ if (typeof value === 'string') {
+ if (!testValues.some(testValue => value.endsWith(testValue))) {
+ return key + ' must end with any of these values: ' + testValues;
+ }
+ } else if (Array.isArray(value)) {
+ let valid = false;
+ for (let i = 0; i < value.length; i++) {
+ for (let j = 0; j < testValues.length; j++) {
+ if (value[i].endsWith(testValues[j])) {
+ valid = true; // set valid flag to true if a match is found
+ break;
+ }
+ }
+ if (valid) {
+ return undefined; // break out of loop if a match is found
+ }
+ }
+
+ if (!valid) {
+ return key + ' must end with any of these values: ' + testValues; // return undefined if no match is found
+ }
+ } else {
+ return key + ' must be a string or an array';
}
};
-
-const getTestValue = options => options?.value ?? options;
-
+/**
+ * @example
+ * value = 30
+ * testValue = 20 (Valid)
+ * = 40 (Fail)
+ *
+ * */
validate.validators.greaterThan = function(value, options, key) {
const testValue = getTestValue(options);
- if (value === undefined || value === null || value <= testValue) {
- return key + 'with value ' + value + ' must be greater than ' + testValue;
+ if (Array.isArray(value) || typeof value === 'string') {
+ return `${key} is not allowed as an array or string`;
+ }
+ if (Array.isArray(testValue)) {
+ if (testValue.length === 1) {
+ if (!(value >= testValue[0])) {
+ return `${key} must be greater than or equal to ${testValue[0]}, but was ${value}`;
+ }
+ } else if (testValue.length > 1) {
+ return key + ' must be an array of length 1';
+ }
+ } else {
+ if (!(value >= testValue)) {
+ return key + ' must be greater than ' + testValue;
+ }
}
};
+/**
+ * @example
+ * value = 30
+ * testValue = 40 (Valid)
+ * = 20 (Fail)
+ *
+ * */
+validate.validators.lessThan = function(value, options, key) {
+ const testValue = getTestValue(options);
+ if (Array.isArray(testValue)) {
+ if (testValue.length === 1) {
+ if (!(value <= testValue[0])) {
+ return `${key} must be less than or equal to ${testValue[0]}, but was ${value}`;
+ }
+ } else if (testValue.length > 1) {
+ return key + ' must be an array of length 1';
+ }
+ } else {
+ if (!(value <= testValue)) {
+ return key + ' must be less than ' + testValue;
+ }
+ }
+};
+/**
+ * @example
+ *
+ * value = 50
+ * testValue = [10,60] (Valid)
+ * = [60, 10] (Valid)
+ * = [0, 10] (Fail)
+ * = [70, 80] (Fail)
+ * = 45 (Fail)
+ * = [45] (Fail)
+ *
+ * */
validate.validators.range = function(value, options, key) {
const testValue = getTestValue(options);
- if (value === undefined || value < testValue[0] || value > testValue[1]) {
- return (
- key +
- 'with value ' +
- value +
- ' must be between ' +
- testValue[0] +
- ' and ' +
- testValue[1]
- );
- }
+ if (Array.isArray(testValue) && testValue.length === 2) {
+ const min = Math.min(testValue[0], testValue[1]);
+ const max = Math.max(testValue[0], testValue[1]);
+ if (value === undefined || value < min || value > max) {
+ return `${key} with value ${value} must be between ${min} and ${max}`;
+ }
+ } else return `${key} must be an array of length 2`;
};
validate.validators.notNull = value =>
- value === null || value === undefined ? 'Value is null' : undefined;
-
+ value === null || value === undefined ? 'Value is null' : undefined;
+const getTestValue = options => {
+ if (Array.isArray(options)) {
+ return options.map(option => option?.value ?? option);
+ } else {
+ return options?.value ?? options;
+ }
+};
+const dicomTagToArray = value => {
+ let dicomArrayValue;
+ if (!Array.isArray(value)) {
+ dicomArrayValue = [value];
+ } else {
+ dicomArrayValue = [...value];
+ }
+ return dicomArrayValue;
+};
export default validate;
diff --git a/platform/core/src/services/HangingProtocolService/lib/validator.test.js b/platform/core/src/services/HangingProtocolService/lib/validator.test.js
index 67b7ac52e..da6f46f04 100644
--- a/platform/core/src/services/HangingProtocolService/lib/validator.test.js
+++ b/platform/core/src/services/HangingProtocolService/lib/validator.test.js
@@ -1,139 +1,570 @@
import validate from './validator.js';
describe('validator', () => {
- const attributeMap = {
- str: 'string',
- upper: 'UPPER',
- num: 3,
- nullValue: null,
- list: ['abc', 'def', 'GHI'],
- };
+ const attributeMap = {
+ str: 'Attenuation Corrected',
+ upper: 'UPPER',
+ num: 3,
+ nullValue: null,
+ list: ['abc', 'def', 'GHI'],
+ listStr: ['Attenuation Corrected'],
+ };
- const options = {
- format: 'grouped',
- };
+ const options = {
+ format: 'grouped',
+ };
- describe('contains', () => {
- it('returns match any list contains', () => {
- expect(
- validate(attributeMap, { list: { contains: 'a' } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { str: { contains: 'i' } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { str: { contains: ['i'] } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { list: { contains: ['a'] } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { list: { contains: ['z', 'd'] } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { list: { contains: ['z'] } }, [options])
- ).not.toBeUndefined();
+ describe('equals', () => {
+ it('returned undefined on strictly equals', () => {
+ expect(
+ validate(attributeMap, { listStr: { equals: ['Attenuation'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { listStr: { equals: 'Attenuation' } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { equals: 'Attenuation Corrected' } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { equals: ['Attenuation Corrected'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { equals: 'Attenuation Corrected' } }, [
+ options,
+ ])
+ ).toBeUndefined();
+
+ expect(
+ validate(
+ attributeMap,
+ { str: { equals: { value: 'Attenuation Corrected' } } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { equals: ['Attenuation Corrected'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { equals: ['Attenuation'] } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { equals: ['abc', 'def', 'GHI'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { equals: ['abc', 'GHI', 'def'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { list: { equals: { value: ['abc', 'def', 'GHI'] } } },
+ [options]
+ )
+ ).toBeUndefined();
+ });
});
- });
+ describe('doesNotEqual', () => {
+ it('returns undefined if value does not equal ', () => {
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { doesNotEqual: 'Attenuation Corrected' } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { doesNotEqual: ['Attenuation Corrected'] } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { listStr: { doesNotEqual: 'Attenuation' } }, [
+ options,
+ ])
+ ).toBeUndefined();
- describe('containsI', () => {
- it('returns match any list contains case insensitive', () => {
- expect(
- validate(attributeMap, { upper: { containsI: ['bye', 'pre'] } }, [
- options,
- ])
- ).not.toBeUndefined();
- expect(
- validate(attributeMap, { list: { containsI: 'hi' } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { list: { containsI: ['hi', 'bye'] } }, [
- options,
- ])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
- options,
- ])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
- ).toBeUndefined();
- expect(
- validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
- options,
- ])
- ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotEqual: 'Attenuation' } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { str: { doesNotEqual: { value: 'Attenuation' } } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotEqual: ['Attenuation'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotEqual: ['abc', 'def'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { list: { doesNotEqual: ['abc', 'GHI', 'def'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { list: { doesNotEqual: ['abc', 'def', 'GHI'] } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ });
});
- });
+ describe('includes', () => {
+ it('returns match any list includes', () => {
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { includes: 'Attenuation Corrected' } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { includes: ['Attenuation Corrected'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { includes: ['Attenuation Corrected', 'Corrected'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { includes: ['Attenuation', 'Corrected'] } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { str: { includes: ['Attenuation Corrected', 'Corrected'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { str: { includes: ['Attenuation', 'Corrected'] } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { includes: ['abc'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { includes: ['GHI', 'HI'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { includes: ['HI', 'bye'] } }, [options])
+ ).not.toBeUndefined();
+ });
+ });
+ describe('doesNotInclude', () => {
+ it('returns undefined if list does not includes', () => {
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { doesNotInclude: 'Attenuation Corrected' } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ {
+ listStr: { doesNotInclude: ['Attenuation Corrected', 'Corrected'] },
+ },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { listStr: { doesNotInclude: ['Attenuation', 'Corrected'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { str: { doesNotInclude: ['Attenuation Corrected', 'Corrected'] } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { str: { doesNotInclude: ['Attenuation', 'Corrected'] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotInclude: ['Corr'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotInclude: 'abc' } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { list: { doesNotInclude: { value: ['abc'] } } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { list: { doesNotInclude: { value: ['att', 'cor'] } } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { list: { doesNotInclude: { value: ['abc', 'def', 'dog'] } } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ });
+ });
+ describe('containsI', () => {
+ it('returns match any list contains case insensitive', () => {
+ expect(
+ validate(attributeMap, { upper: { containsI: ['hi', 'pre'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { containsI: 'hi' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { containsI: ['ghi', 'bye'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ });
+ });
+ describe('contains', () => {
+ it('returns match any list contains', () => {
+ expect(
+ validate(attributeMap, { str: { contains: 'Corr' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { contains: { value: 'Corr' } } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { contains: ['Corr'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { contains: ['corr'] } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { contains: ['Att', 'Wall'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { contains: 'GH' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { contains: ['ab'] } }, [options])
+ ).toBeUndefined();
- describe('equals', () => {
- it('returned undefined on equals', () => {
- expect(
- validate(attributeMap, { str: { equals: attributeMap.str } }, [options])
- ).toBeUndefined();
- expect(
- validate(
- attributeMap,
- { num: { equals: { value: attributeMap.num } } },
- [options]
- )
- ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { contains: ['z', 'bc'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { contains: ['z'] } }, [options])
+ ).not.toBeUndefined();
+ });
});
- it('returns error on not equals', () => {
- expect(
- validate(attributeMap, { str: { equals: 'abc' } }, [options])
- ).not.toBeUndefined();
- expect(
- validate(
- attributeMap,
- { num: { equals: { value: 1 + attributeMap.num } } },
- [options]
- )
- ).not.toBeUndefined();
+ describe('doesNotContain', () => {
+ it('returns undefined if string does not contain specified value', () => {
+ expect(
+ validate(attributeMap, { str: { doesNotContain: ['att', 'wall'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContain: 'Corr' } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContain: 'corr' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContain: { value: 'corr' } } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContain: ['att', 'cor'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContain: ['Att', 'cor'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContain: ['bye', 'hi'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotContain: ['GHI', 'hi'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotContain: ['hi'] } }, [options])
+ ).toBeUndefined();
+ });
});
- });
-
- describe('greaterThan', () => {
- it('returns undefined on greaterThan', () => {
- expect(
- validate(
- attributeMap,
- { num: { greaterThan: { value: attributeMap.num - 1 } } },
- [options]
- )
- ).toBeUndefined();
- expect(
- validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
- options,
- ])
- ).toBeUndefined();
+ describe('doesNotContainI', () => {
+ it('returns undefined if string does not contain specified value', () => {
+ expect(
+ validate(attributeMap, { str: { doesNotContainI: 'corr' } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContainI: 'Corr' } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContainI: ['att', 'cor'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContainI: ['Att', 'wall'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { doesNotContainI: ['bye', 'hi'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotContainI: 'bye' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ });
+ });
+ describe('startsWith', () => {
+ it('returns undefined if string starts with specified value', () => {
+ expect(
+ validate(attributeMap, { str: { startsWith: { value: 'Atte' } } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { startsWith: 'Att' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { startsWith: ['cat', 'dog', 'Att'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { startsWith: ['cat', 'dog'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { startsWith: ['GH'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { startsWith: ['de', 'bye'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { startsWith: ['hi', 'bye'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ });
+ });
+ describe('endsWith', () => {
+ it('returns undefined if string ends with specified value', () => {
+ expect(
+ validate(attributeMap, { str: { endsWith: 'ted' } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { endsWith: { value: 'ted' } } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { endsWith: ['ted'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { endsWith: ['Att'] } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { str: { endsWith: ['cat', 'dog', 'ted'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { endsWith: ['HI'] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { endsWith: ['bc', 'dog', 'ted'] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { list: { endsWith: ['bye', 'dog'] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ });
});
- it('returns error on not greater than', () => {
- expect(
- validate(
- attributeMap,
- { num: { greaterThan: { value: attributeMap.num } } },
- [options]
- )
- ).not.toBeUndefined();
- expect(
- validate(attributeMap, { num: { greaterThan: attributeMap.num } }, [
- options,
- ])
- ).not.toBeUndefined();
+ describe('greaterThan', () => {
+ it('returns undefined on greaterThan', () => {
+ expect(
+ validate(
+ attributeMap,
+ { num: { greaterThan: { value: attributeMap.num - 1 } } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { num: { greaterThan: [attributeMap.num - 1] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(
+ attributeMap,
+ { num: { greaterThan: [attributeMap.num + 1] } },
+ [options]
+ )
+ ).not.toBeUndefined();
+ });
});
-
- it('returns error on undefined value', () => {
- expect(
- validate(
- attributeMap,
- { numUndefined: { greaterThan: { value: 3 } } },
- [options]
- )
- ).not.toBeUndefined();
+ describe('lessThan', () => {
+ it('returns undefined on lessThan', () => {
+ expect(
+ validate(
+ attributeMap,
+ { num: { lessThan: { value: attributeMap.num + 1 } } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { lessThan: attributeMap.num + 1 } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { lessThan: [attributeMap.num + 1] } }, [
+ options,
+ ])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { lessThan: [attributeMap.num - 1] } }, [
+ options,
+ ])
+ ).not.toBeUndefined();
+ });
+ });
+ describe('range', () => {
+ it('returns undefined if the value is between', () => {
+ expect(
+ validate(
+ attributeMap,
+ { num: { range: [attributeMap.num + 1, attributeMap.num - 1] } },
+ [options]
+ )
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { range: [1, 4] } }, [options])
+ ).toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { range: [1, 2] } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { range: [4, 5] } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { range: [5] } }, [options])
+ ).not.toBeUndefined();
+ expect(
+ validate(attributeMap, { num: { range: 5 } }, [options])
+ ).not.toBeUndefined();
+ });
});
- });
});
diff --git a/platform/docs/docs/platform/extensions/modules/hpModule.md b/platform/docs/docs/platform/extensions/modules/hpModule.md
index 67bbd7ec8..0c78b1db3 100644
--- a/platform/docs/docs/platform/extensions/modules/hpModule.md
+++ b/platform/docs/docs/platform/extensions/modules/hpModule.md
@@ -246,7 +246,23 @@ A list of criteria for the protocol along with the provided points for ranking.
- `constraint`: the constraint that needs to be satisfied for the attribute. It accepts a `validator` which can be
[`equals`, `doesNotEqual`, `contains`, `doesNotContain`, `startsWith`, `endsWidth`]
-
+
+ - | Rule | Single Value | Array Value | Example |
+ |--- |--- |--- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | equals | === | All members are === in same order | value = ['abc', 'def', 'GHI']
testValue = 'abc' (Fail)
= ['abc'] (Fail)
= ['abc', 'def', 'GHI'] (Valid)
= ['abc', 'GHI', 'def'] (Fail)
= ['abc', 'def'] (Fail)
value = 'Attenuation Corrected'
testValue = 'Attenuation Corrected' (Valid)
= 'Attenuation' (Fail)
value = ['Attenuation Corrected']
testValue = ['Attenuation Corrected'] (Valid)
= 'Attenuation Corrected' (Valid)
= 'Attenuation' (Fail)
|
+ | doesNotEqual | !== | Any member is !== for the array, either in value, order, or length | value = ['abc', 'def', 'GHI']
testValue = 'abc' (Valid)
= ['abc'] (Valid)
= ['abc', 'def', 'GHI'] (Fail)
= ['abc', 'GHI', 'def'] (Valid)
= ['abc', 'def'] (Valid)
value = 'Attenuation Corrected'
testValue = 'Attenuation Corrected' (Fail)Valid
= 'Attenuation' (Valid)
value = ['Attenuation Corrected']
testValue = ['Attenuation Corrected'] (Fail)
= 'Attenuation Corrected' (Fail)
= 'Attenuation' (Fail) |
+ | includes | Not allowed | Value is equal to one of the values of the array | value = ['abc', 'def', 'GHI']
testValue = ['abc'] (Valid)
= ‘abc’ (Fail)
= [‘abc’] (Fail)
= ‘dog’ (Fail)
= = [‘att’, ‘abc’] (Valid)
= ['abc', 'def', 'dog'] (Valid)
= ['cat', 'dog'] (Fail)
value = 'Attenuation Corrected'
testValue = ['Attenuation Corrected', 'Corrected'] (Valid)
= ['Attenuation', 'Corrected'] (Fail)
value = ['Attenuation Corrected']
testValue = 'Attenuation Corrected' (Fail)
= ['Attenuation Corrected', 'Corrected'] (Valid)
= ['Attenuation', 'Corrected'] (Fail) |
+ | doesNotInclude | Not allowed | Value is not in one of the values of the array | value = ['abc', 'def', 'GHI']
testValue = ‘Corr’ (Valid)
= ‘abc’ (Fail)
= [‘att’, ‘cor’] (Valid)
= ['abc', 'def', 'dog'] (Fail)
value = 'Attenuation Corrected'
testValue = ['Attenuation Corrected', 'Corrected'] (Fail)
= ['Attenuation', 'Corrected'] (Valid)
value = ['Attenuation Corrected']
testValue = 'Attenuation' (Fail)
= ['Attenuation Corrected', 'Corrected'] (Fail)
= ['Attenuation', 'Corrected'] (Valid) |
+ | containsI | String containment (case insensitive) | String containment (case insensitive) is OK for one of the rule values | value = 'Attenuation Corrected'
testValue = ‘Corr’ (Valid)
= ‘corr’ (Valid)
= [‘att’, ‘cor’] (Valid)
= [‘Att’, ‘Wall’] (Valid)
= [‘cat’, ‘dog’] (Fail)
value = ['abc', 'def', 'GHI']
testValue = 'def' (Valid)
= 'dog' (Fail)
= ['gh', 'de'] (Valid)
= ['cat', 'dog'] (Fail)
|
+ | contains | String containment (case sensitive) | String containment (case sensitive) is OK for one of the rule values | value = 'Attenuation Corrected'
testValue = ‘Corr’ (Valid)
= ‘corr’ (Fail)
= [‘att’, ‘cor’] (Fail)
= [‘Att’, ‘Wall’] (Valid)
= [‘cat’, ‘dog’] (Fail)
value = ['abc', 'def', 'GHI']
testValue = 'def' (Valid)
= 'dog' (Fail)
= ['cat', 'de'] (Valid)
= ['cat', 'dog'] (Fail) |
+ | doesNotContain | String containment is false | String containment is false for all values of the array | value = 'Attenuation Corrected'
testValue = ‘Corr’ (Fail)
= ‘corr’ (Valid)
= [‘att’, ‘cor’] (Valid)
= [‘Att’, ‘Wall’] (Fail)
= [‘cat’, ‘dog’] (Valid)
value = ['abc', 'def', 'GHI']
testValue = 'def' (Fail)
= 'dog' (Valid)
= ['cat', 'de'] (Fail)
= ['cat', 'dog'] (Valid) |
+ | doesNotContainI | String containment is false (case insensitive) | String containment (case insensitive) is false for all values of the array | value = 'Attenuation Corrected'
testValue = ‘Corr’ (Fail)
= ‘corr’ (Fail)
= [‘att’, ‘cor’] (Fail)
= [‘Att’, ‘Wall’] (Fail)
= [‘cat’, ‘dog’] (Valid)
value = ['abc', 'def', 'GHI']
testValue = 'DEF' (Fail)
= 'dog' (Valid)
= ['cat', 'gh'] (Fail)
= ['cat', 'dog'] (Valid) |
+ | startsWith | Value begins with characters | Starts with one of the values of the array | value = 'Attenuation Corrected'
testValue = ‘Corr’ (Fail)
= ‘Att’ (Fail)
= ['cat', 'dog', 'Att'] (Valid)
= [‘cat’, ‘dog’] (Fail)
value = ['abc', 'def', 'GHI']
testValue = 'deg' (Valid)
= ['cat', 'GH'] (Valid)
= ['cat', 'gh'] (Fail)
= ['cat', 'dog'] (Fail) |
+ | endsWith | Value ends with characters | ends with one of the value of the array | value = 'Attenuation Corrected'
testValue = ‘TED’ (Fail)
= ‘ted’ (Valid)
= ['cat', 'dog', 'ted'] (Valid)
= [‘cat’, ‘dog’] (Fail)
value = ['abc', 'def', 'GHI']
testValue = 'deg' (Valid)
= ['cat', 'HI'] (Valid)
= ['cat', 'hi'] (Fail)
= ['cat', 'dog'] (Fail) |
+ | greaterThan | value is => to rule | Not applicable | value = 30
testValue = 20 (Valid)
= 40 (Fail)
|
+ | lessThan | value is <= to rule | Not applicable | value = 30
testValue = 40 (Valid)
= 20 (Fail)
|
+ | range | Not applicable | 2 value requested (min and max) | value = 50
testValue = [10,60] (Valid)
= [60, 10] (Valid)
= [0, 10] (Fail)
= [70, 80] (Fail)
= 45 (Fail)
= [45] (Fail) |
+ | notNull | Not Applicable | Not Applicable | No value |
A sample of the matching rule is above which matches against the study description to be PETCT
```js