Skip to content

Commit

Permalink
Merge pull request #452 from MeasureAuthoringTool/MAT-8079/restrictAc…
Browse files Browse the repository at this point in the history
…cessModifiers

MAT-8079 restrict access modifiers
  • Loading branch information
sb-prateekkeerthi authored Feb 4, 2025
2 parents be6c368 + 58c8e9e commit 74e8622
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 5 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"webpack-merge": "^5.8.0"
},
"dependencies": {
"@madie/cql-antlr-parser": "^1.0.11",
"@madie/cql-antlr-parser": "^1.0.12",
"@madie/madie-design-system": "^1.2.41",
"@material-ui/core": "^4.12.4",
"@mui/icons-material": "^5.5.1",
Expand Down
54 changes: 54 additions & 0 deletions src/validations/codeSystemValidation.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import axios from "../api/axios-instance";
import { ServiceConfig, useServiceConfig } from "../api/useServiceConfig";
import ValidateCustomCqlCodes, {
validateAccessModifierErrors,
getCustomCqlCodes,
mapCodeSystemErrorsToTranslationErrors,
} from "./codesystemValidation";
Expand Down Expand Up @@ -386,3 +387,56 @@ describe("Code System validation", () => {
expect(elmTranslationErrors.length).toBe(1);
});
});

describe("Validating for Access Modifiers", () => {
it("generating errors when access modifiers are used in the definitions ", () => {
const definitions = [
{
text: 'define private "SDE Payer":\n ["Patient Characteristic Payer": "Payer Type"]',
start: {
line: 23,
position: 0,
},
stop: {
line: 31,
position: 47,
},
name: "private",
expression: ":",
comment: "test\nnow",
},
{
text: 'define "SDE Race":\n ["Patient Characteristic Race": "Race"]',
start: {
line: 33,
position: 0,
},
stop: {
line: 34,
position: 40,
},
name: '"SDE Race"',
expression: '["Patient Characteristic Race":"Race"]',
},
{
text: 'define public "Qualifying Encounters":\n ( ["Encounter, Performed": "Encounter Inpatient"]\n union ["Encounter, Performed": "Emergency Department Visit"]\n union ["Encounter, Performed": "Acute Inpatient"]\n union ["Encounter, Performed": "Active Bleeding"]\n union ["Encounter, Performed": "Observation Services"] ) Encounter\n where Encounter.relevantPeriod ends during "Measurement Period"',
start: {
line: 40,
position: 0,
},
stop: {
line: 40,
position: 39,
},
name: "public",
expression: ":",
},
];
const accessModifierCqlErrors: ElmTranslationError[] =
validateAccessModifierErrors(definitions);

expect(accessModifierCqlErrors.length).toBe(2);
expect(accessModifierCqlErrors[0].startLine).toBe(30);
expect(accessModifierCqlErrors[1].startLine).toBe(40);
});
});
37 changes: 37 additions & 0 deletions src/validations/codesystemValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,43 @@ export const mapCodeSystemErrorsToTranslationErrors = (
return result;
};

export const validateAccessModifierErrors = (definitions) => {
const result = [];
const accessModifierIncludedDefinitions = definitions.filter((definition) =>
/\bdefine\s+(public|private)\b/.test(definition.text)
);
accessModifierIncludedDefinitions.forEach((def) => {
let errorStartLine;
if (def?.comment) {
const totalLineExcludingCommentsInDefinition =
def.text.split("\n").length;
errorStartLine =
def.stop.line - totalLineExcludingCommentsInDefinition + 1;
} else {
errorStartLine = def.start.line;
}

const cqlObj = {
start: {
line: errorStartLine,
position: def.start.position,
},
stop: {
line: errorStartLine,
position:
def.text.indexOf("\n") !== -1
? def.text.indexOf("\n")
: def.text.length,
},
errorMessage:
"Access modifiers like Public and Private can not be used in MADiE.",
};

result.push(getCqlErrors(cqlObj, "Error", "Access Modifier"));
});
return result;
};

const getCqlErrors = (cqlObj, errorSeverity, errorType) => {
return {
startLine: cqlObj.start.line,
Expand Down
49 changes: 49 additions & 0 deletions src/validations/editorValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,53 @@ describe("Editor Validation Test", () => {
"include FHIRHelpers statement is missing version. Please add a version to the include."
);
});

it("Validate editor definitions show access modifier errors", async () => {
const editorContent: string =
"library AdvancedIllnessandFrailtyExclusion_QICore4 version '5.0.000' \n" +
"using QICore version '4.1.0' \n" +
'define public "Denominator":\n "Initial Population"';

mockedAxios.get.mockImplementation((args) => {
if (
args &&
args.startsWith(mockServiceConfig.terminologyService.baseUrl)
) {
return Promise.resolve({
data: fhirValueset,
status: 200,
});
}
});
mockedAxios.put.mockImplementation((args) => {
if (
args &&
args.startsWith(mockServiceConfig.terminologyService.baseUrl)
) {
return Promise.resolve({
data: customCqlCodesValid,
status: 200,
});
} else if (
args &&
args.startsWith(mockServiceConfig.fhirElmTranslationService.baseUrl)
) {
return Promise.resolve({
data: {
json: JSON.stringify(elmTranslationWithNoErrors),
},
status: 200,
});
}
});
const errorsResult: ValidationResult = await useGetAllErrors(
editorContent,
true
);

expect(errorsResult?.errors.length).toBe(1);
expect(errorsResult?.errors[0].message).toBe(
"Access modifiers like Public and Private can not be used in MADiE."
);
});
});
12 changes: 12 additions & 0 deletions src/validations/editorValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import CqlResult from "@madie/cql-antlr-parser/dist/src/dto/CqlResult";
import { CqlAntlr } from "@madie/cql-antlr-parser/dist/src";
import ValidateCustomCqlCodes, {
getCustomCqlCodes,
validateAccessModifierErrors,
mapCodeSystemErrorsToTranslationErrors,
} from "../validations/codesystemValidation";
import TranslateCql from "../validations/elmTranslateValidation";
Expand Down Expand Up @@ -49,6 +50,10 @@ export const useGetAllErrors = async (
let allErrorsArray: ElmTranslationError[] =
updateErrorTypeForTranslationErrors(translationResults);

// returning errors if the definitions have access modifiers
const accessModifierCqlErrors: ElmTranslationError[] =
validateAccessModifierErrors(cqlResult.expressionDefinitions);

// Filter out external errors for include error type
// find will return the first found object
let externalErrors: ElmTranslationExternalError[] = [];
Expand All @@ -69,6 +74,13 @@ export const useGetAllErrors = async (
allErrorsArray.push(valueSet);
});
}

if (accessModifierCqlErrors && accessModifierCqlErrors.length > 0) {
accessModifierCqlErrors.map((modifierError) =>
allErrorsArray.push(modifierError)
);
}

return {
externalErrors: externalErrors,
translation: translationResults,
Expand Down

0 comments on commit 74e8622

Please sign in to comment.