@openhealth/oht-custom-parser-lib 0.1.11 → 0.1.12

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.
Files changed (37) hide show
  1. package/dist/index.d.ts +11 -0
  2. package/dist/index.js +60 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/service/auxiliaryFunctions.service.d.ts +19 -0
  5. package/dist/service/auxiliaryFunctions.service.js +64 -0
  6. package/dist/service/auxiliaryFunctions.service.js.map +1 -0
  7. package/dist/service/ohtMeasurementsExtractor.service.d.ts +31 -0
  8. package/dist/service/ohtMeasurementsExtractor.service.js +403 -0
  9. package/dist/service/ohtMeasurementsExtractor.service.js.map +1 -0
  10. package/dist/service/reportCreator.service.d.ts +8 -0
  11. package/dist/service/reportCreator.service.js +129 -0
  12. package/dist/service/reportCreator.service.js.map +1 -0
  13. package/dist/service/slackMessages.service.d.ts +9 -0
  14. package/dist/service/slackMessages.service.js +92 -0
  15. package/dist/service/slackMessages.service.js.map +1 -0
  16. package/dist/types/custom-parser.types.d.ts +56 -0
  17. package/dist/types/custom-parser.types.js +28 -0
  18. package/dist/types/custom-parser.types.js.map +1 -0
  19. package/dist/types/oht.types.d.ts +300 -0
  20. package/dist/types/oht.types.js +90 -0
  21. package/dist/types/oht.types.js.map +1 -0
  22. package/dist/types/slackMessages.types.d.ts +5 -0
  23. package/dist/types/slackMessages.types.js +3 -0
  24. package/dist/types/slackMessages.types.js.map +1 -0
  25. package/dist/util-ts/dataUtils.d.ts +3 -0
  26. package/dist/util-ts/dataUtils.js +19 -0
  27. package/dist/util-ts/dataUtils.js.map +1 -0
  28. package/dist/util-ts/googleStorageUtils.d.ts +3 -0
  29. package/dist/util-ts/googleStorageUtils.js +47 -0
  30. package/dist/util-ts/googleStorageUtils.js.map +1 -0
  31. package/dist/util-ts/pinoLogger.d.ts +12 -0
  32. package/dist/util-ts/pinoLogger.js +31 -0
  33. package/dist/util-ts/pinoLogger.js.map +1 -0
  34. package/dist/util-ts/regexUtils.d.ts +2 -0
  35. package/dist/util-ts/regexUtils.js +20 -0
  36. package/dist/util-ts/regexUtils.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,11 @@
1
+ export { postDataImportFileUploadToCore, makeApiCallWithRetry, parseErrorObj } from './service/reportCreator.service';
2
+ export { parseExternalPatientId, parseGender, isPatientAgeValid, handleRejection, queryFileUploadsWithFilters, postFileUploadSetStatus } from './service/auxiliaryFunctions.service';
3
+ export { ohtMeasurementsExtractor, checkValueForPlausibleValues, extractReferenceRanges, extractReferenceAnnotation, parseExamValue, getRangeFromPositionAndRegex, extractUnit, extractValueFromGreaterLowerThan } from './service/ohtMeasurementsExtractor.service';
4
+ export { getSlackFileIssueNotificationMessage, sendMessageToSlack, aggregateMessages } from './service/slackMessages.service';
5
+ export { LabToOhtContract, LabToOhtMapper, UnknownMeasurementExtraction, ReferenceAsAnnotation, UnitExtraction, RangeExtraction, RangeExtractionResponse, ValueExtraction, unitSynonyms, } from './types/custom-parser.types';
6
+ export { AcfBiomarkerRangeAnnotationCheck, AcfBiomarkerGenericDisclaimerLogic, ManualCheck, BiomarkerCompatibility, ReferenceRangeType, AcfReferenceRange, VisualRange, NameAlias, AlternativeUnit, BiomarkerAcf, Biomarker, PipelineStep, DigitizationStatus, MeasurementValueComparator, BiomarkerValueType, DataImportFileUploadStatus, Sex, Digitization, PatientInfo, UnknownMeasurement, Measurement, DataImportFileUpload, MessagePayload, SignedUpload, ReportStyleConfig, LanguageCode, BiomarkerCustomisation, PartnerCustomPanel, ReportDisplaySettings, ReportCustomisation, OHTPartner, } from './types/oht.types';
7
+ export { SlackMessage } from './types/slackMessages.types';
8
+ export { extractValue, isBiomarkerValueNumerical, isBiomarkerExternalNoVisualRange } from './util-ts/dataUtils';
9
+ export { readFileFromBucket, uploadFileBufferToGCS } from './util-ts/googleStorageUtils';
10
+ export { default as pinoLogger } from './util-ts/pinoLogger';
11
+ export { getGreaterThanPatterns, getLowerThanPatterns } from './util-ts/regexUtils';
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getLowerThanPatterns = exports.getGreaterThanPatterns = exports.pinoLogger = exports.uploadFileBufferToGCS = exports.readFileFromBucket = exports.isBiomarkerExternalNoVisualRange = exports.isBiomarkerValueNumerical = exports.extractValue = exports.Sex = exports.DataImportFileUploadStatus = exports.BiomarkerValueType = exports.MeasurementValueComparator = exports.DigitizationStatus = exports.PipelineStep = exports.ReferenceRangeType = exports.BiomarkerCompatibility = exports.ManualCheck = exports.AcfBiomarkerGenericDisclaimerLogic = exports.AcfBiomarkerRangeAnnotationCheck = exports.unitSynonyms = exports.aggregateMessages = exports.sendMessageToSlack = exports.getSlackFileIssueNotificationMessage = exports.extractValueFromGreaterLowerThan = exports.extractUnit = exports.getRangeFromPositionAndRegex = exports.parseExamValue = exports.extractReferenceAnnotation = exports.extractReferenceRanges = exports.checkValueForPlausibleValues = exports.ohtMeasurementsExtractor = exports.postFileUploadSetStatus = exports.queryFileUploadsWithFilters = exports.handleRejection = exports.isPatientAgeValid = exports.parseGender = exports.parseExternalPatientId = exports.parseErrorObj = exports.makeApiCallWithRetry = exports.postDataImportFileUploadToCore = void 0;
7
+ // ### SERVICES ###
8
+ var reportCreator_service_1 = require("./service/reportCreator.service");
9
+ Object.defineProperty(exports, "postDataImportFileUploadToCore", { enumerable: true, get: function () { return reportCreator_service_1.postDataImportFileUploadToCore; } });
10
+ Object.defineProperty(exports, "makeApiCallWithRetry", { enumerable: true, get: function () { return reportCreator_service_1.makeApiCallWithRetry; } });
11
+ Object.defineProperty(exports, "parseErrorObj", { enumerable: true, get: function () { return reportCreator_service_1.parseErrorObj; } });
12
+ var auxiliaryFunctions_service_1 = require("./service/auxiliaryFunctions.service");
13
+ Object.defineProperty(exports, "parseExternalPatientId", { enumerable: true, get: function () { return auxiliaryFunctions_service_1.parseExternalPatientId; } });
14
+ Object.defineProperty(exports, "parseGender", { enumerable: true, get: function () { return auxiliaryFunctions_service_1.parseGender; } });
15
+ Object.defineProperty(exports, "isPatientAgeValid", { enumerable: true, get: function () { return auxiliaryFunctions_service_1.isPatientAgeValid; } });
16
+ Object.defineProperty(exports, "handleRejection", { enumerable: true, get: function () { return auxiliaryFunctions_service_1.handleRejection; } });
17
+ Object.defineProperty(exports, "queryFileUploadsWithFilters", { enumerable: true, get: function () { return auxiliaryFunctions_service_1.queryFileUploadsWithFilters; } });
18
+ Object.defineProperty(exports, "postFileUploadSetStatus", { enumerable: true, get: function () { return auxiliaryFunctions_service_1.postFileUploadSetStatus; } });
19
+ var ohtMeasurementsExtractor_service_1 = require("./service/ohtMeasurementsExtractor.service");
20
+ Object.defineProperty(exports, "ohtMeasurementsExtractor", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.ohtMeasurementsExtractor; } });
21
+ Object.defineProperty(exports, "checkValueForPlausibleValues", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.checkValueForPlausibleValues; } });
22
+ Object.defineProperty(exports, "extractReferenceRanges", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.extractReferenceRanges; } });
23
+ Object.defineProperty(exports, "extractReferenceAnnotation", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.extractReferenceAnnotation; } });
24
+ Object.defineProperty(exports, "parseExamValue", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.parseExamValue; } });
25
+ Object.defineProperty(exports, "getRangeFromPositionAndRegex", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.getRangeFromPositionAndRegex; } });
26
+ Object.defineProperty(exports, "extractUnit", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.extractUnit; } });
27
+ Object.defineProperty(exports, "extractValueFromGreaterLowerThan", { enumerable: true, get: function () { return ohtMeasurementsExtractor_service_1.extractValueFromGreaterLowerThan; } });
28
+ var slackMessages_service_1 = require("./service/slackMessages.service");
29
+ Object.defineProperty(exports, "getSlackFileIssueNotificationMessage", { enumerable: true, get: function () { return slackMessages_service_1.getSlackFileIssueNotificationMessage; } });
30
+ Object.defineProperty(exports, "sendMessageToSlack", { enumerable: true, get: function () { return slackMessages_service_1.sendMessageToSlack; } });
31
+ Object.defineProperty(exports, "aggregateMessages", { enumerable: true, get: function () { return slackMessages_service_1.aggregateMessages; } });
32
+ // ### TYPES ###
33
+ var custom_parser_types_1 = require("./types/custom-parser.types");
34
+ Object.defineProperty(exports, "unitSynonyms", { enumerable: true, get: function () { return custom_parser_types_1.unitSynonyms; } });
35
+ var oht_types_1 = require("./types/oht.types");
36
+ Object.defineProperty(exports, "AcfBiomarkerRangeAnnotationCheck", { enumerable: true, get: function () { return oht_types_1.AcfBiomarkerRangeAnnotationCheck; } });
37
+ Object.defineProperty(exports, "AcfBiomarkerGenericDisclaimerLogic", { enumerable: true, get: function () { return oht_types_1.AcfBiomarkerGenericDisclaimerLogic; } });
38
+ Object.defineProperty(exports, "ManualCheck", { enumerable: true, get: function () { return oht_types_1.ManualCheck; } });
39
+ Object.defineProperty(exports, "BiomarkerCompatibility", { enumerable: true, get: function () { return oht_types_1.BiomarkerCompatibility; } });
40
+ Object.defineProperty(exports, "ReferenceRangeType", { enumerable: true, get: function () { return oht_types_1.ReferenceRangeType; } });
41
+ Object.defineProperty(exports, "PipelineStep", { enumerable: true, get: function () { return oht_types_1.PipelineStep; } });
42
+ Object.defineProperty(exports, "DigitizationStatus", { enumerable: true, get: function () { return oht_types_1.DigitizationStatus; } });
43
+ Object.defineProperty(exports, "MeasurementValueComparator", { enumerable: true, get: function () { return oht_types_1.MeasurementValueComparator; } });
44
+ Object.defineProperty(exports, "BiomarkerValueType", { enumerable: true, get: function () { return oht_types_1.BiomarkerValueType; } });
45
+ Object.defineProperty(exports, "DataImportFileUploadStatus", { enumerable: true, get: function () { return oht_types_1.DataImportFileUploadStatus; } });
46
+ Object.defineProperty(exports, "Sex", { enumerable: true, get: function () { return oht_types_1.Sex; } });
47
+ // ### UTIL-TS ###
48
+ var dataUtils_1 = require("./util-ts/dataUtils");
49
+ Object.defineProperty(exports, "extractValue", { enumerable: true, get: function () { return dataUtils_1.extractValue; } });
50
+ Object.defineProperty(exports, "isBiomarkerValueNumerical", { enumerable: true, get: function () { return dataUtils_1.isBiomarkerValueNumerical; } });
51
+ Object.defineProperty(exports, "isBiomarkerExternalNoVisualRange", { enumerable: true, get: function () { return dataUtils_1.isBiomarkerExternalNoVisualRange; } });
52
+ var googleStorageUtils_1 = require("./util-ts/googleStorageUtils");
53
+ Object.defineProperty(exports, "readFileFromBucket", { enumerable: true, get: function () { return googleStorageUtils_1.readFileFromBucket; } });
54
+ Object.defineProperty(exports, "uploadFileBufferToGCS", { enumerable: true, get: function () { return googleStorageUtils_1.uploadFileBufferToGCS; } });
55
+ var pinoLogger_1 = require("./util-ts/pinoLogger");
56
+ Object.defineProperty(exports, "pinoLogger", { enumerable: true, get: function () { return __importDefault(pinoLogger_1).default; } });
57
+ var regexUtils_1 = require("./util-ts/regexUtils");
58
+ Object.defineProperty(exports, "getGreaterThanPatterns", { enumerable: true, get: function () { return regexUtils_1.getGreaterThanPatterns; } });
59
+ Object.defineProperty(exports, "getLowerThanPatterns", { enumerable: true, get: function () { return regexUtils_1.getLowerThanPatterns; } });
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;AAAA,mBAAmB;AACnB,yEAEyC;AADvC,uIAAA,8BAA8B,OAAA;AAAE,6HAAA,oBAAoB,OAAA;AAAE,sHAAA,aAAa,OAAA;AAErE,mFAO8C;AAN5C,oIAAA,sBAAsB,OAAA;AACtB,yHAAA,WAAW,OAAA;AACX,+HAAA,iBAAiB,OAAA;AACjB,6HAAA,eAAe,OAAA;AACf,yIAAA,2BAA2B,OAAA;AAC3B,qIAAA,uBAAuB,OAAA;AAEzB,+FASoD;AARlD,4IAAA,wBAAwB,OAAA;AACxB,gJAAA,4BAA4B,OAAA;AAC5B,0IAAA,sBAAsB,OAAA;AACtB,8IAAA,0BAA0B,OAAA;AAC1B,kIAAA,cAAc,OAAA;AACd,gJAAA,4BAA4B,OAAA;AAC5B,+HAAA,WAAW,OAAA;AACX,oJAAA,gCAAgC,OAAA;AAElC,yEAEyC;AADvC,6IAAA,oCAAoC,OAAA;AAAE,2HAAA,kBAAkB,OAAA;AAAE,0HAAA,iBAAiB,OAAA;AAG7E,gBAAgB;AAChB,mEAUqC;AADnC,mHAAA,YAAY,OAAA;AAEd,+CAgC2B;AA/BzB,6HAAA,gCAAgC,OAAA;AAChC,+HAAA,kCAAkC,OAAA;AAClC,wGAAA,WAAW,OAAA;AACX,mHAAA,sBAAsB,OAAA;AACtB,+GAAA,kBAAkB,OAAA;AAOlB,yGAAA,YAAY,OAAA;AACZ,+GAAA,kBAAkB,OAAA;AAClB,uHAAA,0BAA0B,OAAA;AAC1B,+GAAA,kBAAkB,OAAA;AAClB,uHAAA,0BAA0B,OAAA;AAC1B,gGAAA,GAAG,OAAA;AAkBL,kBAAkB;AAClB,iDAA8G;AAAtG,yGAAA,YAAY,OAAA;AAAE,sHAAA,yBAAyB,OAAA;AAAE,6HAAA,gCAAgC,OAAA;AACjF,mEAAyF;AAAhF,wHAAA,kBAAkB,OAAA;AAAE,2HAAA,qBAAqB,OAAA;AAClD,mDAA2D;AAAnD,yHAAA,OAAO,OAAc;AAC7B,mDAAkF;AAA1E,oHAAA,sBAAsB,OAAA;AAAE,kHAAA,oBAAoB,OAAA"}
@@ -0,0 +1,19 @@
1
+ import { SlackMessage } from '../types/slackMessages.types';
2
+ import { DataImportFileUpload, DataImportFileUploadStatus, Sex } from "../types/oht.types";
3
+ declare function isPatientAgeValid(documentDate?: Date, patientBirthdate?: Date): boolean;
4
+ declare function parseExternalPatientId(patientExternalId?: string): boolean;
5
+ declare function parseGender(patientGender?: string): {
6
+ sex: Sex;
7
+ isGenderCorrectlyParsed: boolean;
8
+ };
9
+ declare function handleRejection(parseType: string, slackMessages: SlackMessage[], type?: string): {
10
+ rejectedStatus: string;
11
+ rejectReason: string;
12
+ };
13
+ export interface FileUploadFilter {
14
+ field: string;
15
+ search: string;
16
+ }
17
+ declare function queryFileUploadsWithFilters(filters: FileUploadFilter[], ohtCoreApiKey: string): Promise<DataImportFileUpload[]>;
18
+ declare function postFileUploadSetStatus(status: DataImportFileUploadStatus, fileUploadId: string, filename: string, ohtCoreApiKey: string): Promise<DataImportFileUpload>;
19
+ export { parseExternalPatientId, parseGender, isPatientAgeValid, handleRejection, queryFileUploadsWithFilters, postFileUploadSetStatus };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseExternalPatientId = parseExternalPatientId;
7
+ exports.parseGender = parseGender;
8
+ exports.isPatientAgeValid = isPatientAgeValid;
9
+ exports.handleRejection = handleRejection;
10
+ exports.queryFileUploadsWithFilters = queryFileUploadsWithFilters;
11
+ exports.postFileUploadSetStatus = postFileUploadSetStatus;
12
+ const moment_1 = __importDefault(require("moment/moment"));
13
+ const reportCreator_service_1 = require("./reportCreator.service");
14
+ const pinoLogger_1 = __importDefault(require("../util-ts/pinoLogger"));
15
+ const oht_types_1 = require("../types/oht.types");
16
+ const logger = (0, pinoLogger_1.default)();
17
+ function isPatientAgeValid(documentDate, patientBirthdate) {
18
+ if (!patientBirthdate || !documentDate)
19
+ return false;
20
+ const patientAge = (0, moment_1.default)(documentDate).diff(patientBirthdate, 'years');
21
+ return patientAge >= 18 && patientAge <= 130;
22
+ }
23
+ function parseExternalPatientId(patientExternalId) {
24
+ return patientExternalId !== undefined && patientExternalId.length > 0;
25
+ }
26
+ function parseGender(patientGender) {
27
+ const gender = patientGender?.toLowerCase();
28
+ switch (gender) {
29
+ case 'masculino':
30
+ case 'male':
31
+ return { sex: oht_types_1.Sex.MALE, isGenderCorrectlyParsed: true };
32
+ case 'feminino':
33
+ case 'female':
34
+ return { sex: oht_types_1.Sex.FEMALE, isGenderCorrectlyParsed: true };
35
+ default:
36
+ return { sex: oht_types_1.Sex.OTHER, isGenderCorrectlyParsed: false };
37
+ }
38
+ }
39
+ function handleRejection(parseType, slackMessages, type = 'ERROR') {
40
+ let rejectedStatus = 'REJECTED';
41
+ let rejectReason = `Could not parse ${parseType}`;
42
+ slackMessages.push({
43
+ type: type,
44
+ message: `File REJECTED, ${parseType} not parsed correctly:`,
45
+ });
46
+ return { rejectedStatus, rejectReason };
47
+ }
48
+ async function queryFileUploadsWithFilters(filters, ohtCoreApiKey) {
49
+ const OHT_CORE_URL = process.env.OHT_CORE_URL;
50
+ const ohtCoreUrl = `${OHT_CORE_URL}/v1/file-uploads/query`;
51
+ const queryData = {
52
+ "filters": [...filters]
53
+ };
54
+ const queryResponse = await (0, reportCreator_service_1.makeApiCallWithRetry)('post', ohtCoreUrl, queryData, ohtCoreApiKey);
55
+ return queryResponse?.data?.items;
56
+ }
57
+ async function postFileUploadSetStatus(status, fileUploadId, filename, ohtCoreApiKey) {
58
+ const OHT_CORE_URL = process.env.OHT_CORE_URL;
59
+ const ohtCoreFileUploadSetStatusUrl = `${OHT_CORE_URL}/v1/file-uploads/status/set/${fileUploadId}`;
60
+ const processingResponse = await (0, reportCreator_service_1.makeApiCallWithRetry)('post', ohtCoreFileUploadSetStatusUrl, { status }, ohtCoreApiKey);
61
+ logger.info({ resp: processingResponse?.data }, `Resp: POST status: ${status} /file-uploads/${fileUploadId}, filename: ${filename}`);
62
+ return processingResponse?.data;
63
+ }
64
+ //# sourceMappingURL=auxiliaryFunctions.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auxiliaryFunctions.service.js","sourceRoot":"","sources":["../../service/auxiliaryFunctions.service.ts"],"names":[],"mappings":";;;;;AA6FE,wDAAsB;AACtB,kCAAW;AACX,8CAAiB;AACjB,0CAAe;AACf,kEAA2B;AAC3B,0DAAuB;AAlGzB,2DAAmC;AAEnC,mEAA6D;AAC7D,uEAA+C;AAC/C,kDAAyF;AACzF,MAAM,MAAM,GAAG,IAAA,oBAAU,GAAE,CAAC;AAE5B,SAAS,iBAAiB,CAAC,YAAmB,EAAE,gBAAuB;IACnE,IAAI,CAAC,gBAAgB,IAAI,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAErD,MAAM,UAAU,GAAG,IAAA,gBAAM,EAAC,YAAY,CAAC,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACxE,OAAO,UAAU,IAAI,EAAE,IAAI,UAAU,IAAI,GAAG,CAAC;AACjD,CAAC;AAED,SAAS,sBAAsB,CAAC,iBAA0B;IACtD,OAAO,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,WAAW,CAAC,aAAsB;IACvC,MAAM,MAAM,GAAG,aAAa,EAAE,WAAW,EAAE,CAAC;IAE5C,QAAQ,MAAM,EAAE,CAAC;QACb,KAAK,WAAW,CAAC;QACjB,KAAK,MAAM;YACP,OAAO,EAAE,GAAG,EAAE,eAAG,CAAC,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;QAC5D,KAAK,UAAU,CAAC;QAChB,KAAK,QAAQ;YACT,OAAO,EAAE,GAAG,EAAE,eAAG,CAAC,MAAM,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;QAC9D;YACI,OAAO,EAAE,GAAG,EAAE,eAAG,CAAC,KAAK,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC;IAClE,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,SAAiB,EAAE,aAA6B,EAAE,IAAI,GAAG,OAAO;IACrF,IAAI,cAAc,GAAG,UAAU,CAAC;IAChC,IAAI,YAAY,GAAG,mBAAmB,SAAS,EAAE,CAAC;IAElD,aAAa,CAAC,IAAI,CAAC;QACf,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,kBAAkB,SAAS,wBAAwB;KAC/D,CAAC,CAAC;IAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,CAAA;AAC3C,CAAC;AAOD,KAAK,UAAU,2BAA2B,CAAC,OAA2B,EAAE,aAAqB;IACzF,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC9C,MAAM,UAAU,GAAG,GAAG,YAAY,wBAAwB,CAAA;IAE1D,MAAM,SAAS,GAAG;QACd,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC;KAC1B,CAAA;IAED,MAAM,aAAa,GAAG,MAAM,IAAA,4CAAoB,EAC9C,MAAM,EACN,UAAU,EACV,SAAS,EACT,aAAa,CACd,CAAC;IAEF,OAAO,aAAa,EAAE,IAAI,EAAE,KAAK,CAAA;AACrC,CAAC;AAED,KAAK,UAAU,uBAAuB,CACpC,MAAkC,EAClC,YAAoB,EACpB,QAAgB,EAChB,aAAqB;IAEnB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC9C,MAAM,6BAA6B,GAAG,GAAG,YAAY,+BAA+B,YAAY,EAAE,CAAC;IAEnG,MAAM,kBAAkB,GAAG,MAAM,IAAA,4CAAoB,EACnD,MAAM,EACN,6BAA6B,EAC7B,EAAC,MAAM,EAAC,EACR,aAAa,CACd,CAAC;IACF,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAClC,sBAAsB,MAAM,kBAAkB,YAAY,eAAe,QAAQ,EAAE,CACpF,CAAC;IAEF,OAAO,kBAAkB,EAAE,IAAI,CAAC;AACpC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { LabToOhtContract, LabToOhtMapper, RangeExtraction, RangeExtractionResponse, UnitExtraction, ValueExtraction } from "../types/custom-parser.types";
2
+ import { Biomarker, BiomarkerValueType, Measurement, MeasurementValueComparator, PatientInfo, UnknownMeasurement } from "../types/oht.types";
3
+ declare function extractUnit(unitExtraction: UnitExtraction | undefined, rawData: any, ohtBiomarker: Biomarker): {
4
+ unit: string;
5
+ isUnitParsedCorrectly: boolean;
6
+ };
7
+ declare function extractReferenceAnnotation(labToOhtMapper: LabToOhtMapper, rawExam: any, patientInfo: PatientInfo, documentDate?: Date): any;
8
+ declare const getRangeFromPositionAndRegex: (rangeExtraction: RangeExtraction, rawData: any) => {
9
+ from: number | undefined;
10
+ to: number | undefined;
11
+ };
12
+ declare function extractReferenceRanges(labToOhtMapper: LabToOhtMapper, rawData: any, patientInfo: PatientInfo, documentDate?: Date): RangeExtractionResponse;
13
+ declare function extractValueFromGreaterLowerThan(value: string): {
14
+ extractedValue: number | null;
15
+ extractedValueComparator: MeasurementValueComparator | null;
16
+ valueParsedCorrectly: boolean;
17
+ };
18
+ declare function parseExamValue(rawExamObj: any, valueExtraction: ValueExtraction | undefined, ohtBiomarker: Biomarker): {
19
+ valueType: BiomarkerValueType;
20
+ alphanumericalValue: string | null;
21
+ numberValue: number | null;
22
+ valueComparator: MeasurementValueComparator;
23
+ isValueParsedCorrectly: boolean;
24
+ };
25
+ declare function checkValueForPlausibleValues(labToOhtMapper: LabToOhtMapper, ohtBiomarker: Biomarker, unit: string, value: number, isUnitParsedCorrectly: boolean): boolean;
26
+ declare function ohtMeasurementsExtractor(labToOhtContract: LabToOhtContract, ohtCoreApiKey: string): Promise<{
27
+ measurements: Measurement[];
28
+ unknownMeasurements: UnknownMeasurement[];
29
+ isReportCorrectlyParsed: boolean;
30
+ }>;
31
+ export { ohtMeasurementsExtractor, checkValueForPlausibleValues, extractReferenceRanges, extractReferenceAnnotation, parseExamValue, getRangeFromPositionAndRegex, extractUnit, extractValueFromGreaterLowerThan };
@@ -0,0 +1,403 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getRangeFromPositionAndRegex = void 0;
7
+ exports.ohtMeasurementsExtractor = ohtMeasurementsExtractor;
8
+ exports.checkValueForPlausibleValues = checkValueForPlausibleValues;
9
+ exports.extractReferenceRanges = extractReferenceRanges;
10
+ exports.extractReferenceAnnotation = extractReferenceAnnotation;
11
+ exports.parseExamValue = parseExamValue;
12
+ exports.extractUnit = extractUnit;
13
+ exports.extractValueFromGreaterLowerThan = extractValueFromGreaterLowerThan;
14
+ const custom_parser_types_1 = require("../types/custom-parser.types");
15
+ const dataUtils_1 = require("../util-ts/dataUtils");
16
+ const regexUtils_1 = require("../util-ts/regexUtils");
17
+ const pinoLogger_1 = __importDefault(require("../util-ts/pinoLogger"));
18
+ const reportCreator_service_1 = require("./reportCreator.service");
19
+ const oht_types_1 = require("../types/oht.types");
20
+ const logger = (0, pinoLogger_1.default)();
21
+ const OHT_CORE_URL = process.env.OHT_CORE_URL;
22
+ let filename = '';
23
+ function extractUnit(unitExtraction, rawData, ohtBiomarker) {
24
+ if (!(0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker)) {
25
+ return { unit: "None", isUnitParsedCorrectly: true };
26
+ }
27
+ // If there's a function to extract the unit, use it
28
+ if (unitExtraction && unitExtraction?.extractionFunc) {
29
+ const extractedUnitExtraction = unitExtraction.extractionFunc(rawData);
30
+ return { unit: extractedUnitExtraction ?? '', isUnitParsedCorrectly: !!extractedUnitExtraction };
31
+ }
32
+ const unit = (0, dataUtils_1.extractValue)(rawData, unitExtraction?.unitPosition);
33
+ let unitLowerCase = unit?.toLowerCase();
34
+ unitLowerCase = unitLowerCase?.replaceAll(/ /g, '') ?? '';
35
+ const standardUnit = ohtBiomarker.acf.standardUnit;
36
+ const allBmOhtUnits = [
37
+ standardUnit?.toLowerCase(),
38
+ ...ohtBiomarker.acf?.alternativeUnits
39
+ ?.map((bmAlternative) => bmAlternative.name.toLowerCase()) ?? []
40
+ ];
41
+ // First test if the biomarker has the unit explicit in the 'unity' field
42
+ const allUnitContainsJsonUnit = allBmOhtUnits.includes(unitLowerCase);
43
+ if (unitLowerCase?.length > 0 && allUnitContainsJsonUnit) {
44
+ return {
45
+ unit: unit?.replaceAll(/ /g, ''),
46
+ isUnitParsedCorrectly: true
47
+ };
48
+ }
49
+ // Check if there are any Synonym configured
50
+ const allUnitContainsJsonUnitSynonyms = allBmOhtUnits.includes(custom_parser_types_1.unitSynonyms[unitLowerCase]?.toLowerCase());
51
+ if (unitLowerCase?.length > 0 && allUnitContainsJsonUnitSynonyms) {
52
+ return { unit: custom_parser_types_1.unitSynonyms[unitLowerCase], isUnitParsedCorrectly: true };
53
+ }
54
+ if (unitExtraction?.predefinedUnit) {
55
+ const allUnitContainsUnitFromOhtMap = allBmOhtUnits.includes(unitExtraction.predefinedUnit.toLowerCase());
56
+ // If the 'unity' field is not present, try to get the unit from the biomarker map
57
+ return { unit: unitExtraction?.predefinedUnit, isUnitParsedCorrectly: allUnitContainsUnitFromOhtMap };
58
+ }
59
+ if (unitExtraction?.extractionRegex) {
60
+ const regex = new RegExp(unitExtraction.extractionRegex);
61
+ const match = rawData.match(regex);
62
+ const allUnitContainsUnitMatch = allBmOhtUnits.includes(match?.[1]?.toLowerCase());
63
+ if (match?.[1] && allUnitContainsUnitMatch) {
64
+ return { unit: match?.[1], isUnitParsedCorrectly: true };
65
+ }
66
+ }
67
+ return { unit: '', isUnitParsedCorrectly: false };
68
+ }
69
+ function extractReferenceAnnotation(labToOhtMapper, rawExam, patientInfo, documentDate) {
70
+ const annotationExtractionFunc = labToOhtMapper?.referenceAsAnnotation?.extractionFunc;
71
+ if (annotationExtractionFunc) {
72
+ return annotationExtractionFunc(rawExam, labToOhtMapper, patientInfo, documentDate);
73
+ }
74
+ else {
75
+ const extractedReference = (0, dataUtils_1.extractValue)(rawExam, labToOhtMapper?.referenceAsAnnotation?.position);
76
+ const reference = extractedReference?.valor?.trim();
77
+ return reference?.length > 0 ? reference : extractedReference?.val?.trim();
78
+ }
79
+ }
80
+ const getRangeFromPositionAndRegex = (rangeExtraction, rawData) => {
81
+ const extractionRegex = rangeExtraction.extractionRegex;
82
+ const rangePosition = rangeExtraction.rangePosition;
83
+ const regex = typeof extractionRegex === 'string' ? new RegExp(extractionRegex) : extractionRegex;
84
+ const value = (0, dataUtils_1.extractValue)(rawData, rangePosition);
85
+ if (regex) {
86
+ let match = regex.exec(value);
87
+ if (match) {
88
+ // Check length of match
89
+ // If length is 2, it means that the range is a single value
90
+ // If length is 3, it means that the range has two values
91
+ const inferior = parseFloat(match[1].replaceAll('.', '').replaceAll(',', '.'));
92
+ const superior = parseFloat(match[match.length - 1].replaceAll('.', '').replaceAll(',', '.'));
93
+ return {
94
+ from: inferior,
95
+ to: superior,
96
+ };
97
+ }
98
+ }
99
+ return {
100
+ from: undefined,
101
+ to: undefined,
102
+ };
103
+ };
104
+ exports.getRangeFromPositionAndRegex = getRangeFromPositionAndRegex;
105
+ function extractReferenceRanges(labToOhtMapper, rawData, patientInfo, documentDate) {
106
+ // WIP
107
+ const nullRangeNotParsedCorrectly = { from: null, to: null, isRangeParsedCorrectly: false };
108
+ const nullRangeParsedCorrectly = { from: null, to: null, isRangeParsedCorrectly: true };
109
+ // if internalRange return null, but is parsed correctly
110
+ if (labToOhtMapper?.rangeExtraction?.useInternalRange) {
111
+ //logger.info(`Using internalRange for biomarker ${ohtBiomarkerMap.ohtBmId}, key: ${ohtBiomarkerMap.labiKey}, filename: ${filename}`)
112
+ return nullRangeParsedCorrectly;
113
+ } // if internalRange return null
114
+ // Each lab has a "default" range structure.
115
+ // We need a default extraction function for each lab
116
+ // Here we receive from the custom parser a function inside the RangeExtraction object
117
+ let rangeExtractionResult = labToOhtMapper?.rangeExtraction?.defaultRangeExtractionFunc
118
+ ? labToOhtMapper.rangeExtraction.defaultRangeExtractionFunc(labToOhtMapper, rawData)
119
+ : nullRangeNotParsedCorrectly;
120
+ if (rangeExtractionResult.isRangeParsedCorrectly) {
121
+ return rangeExtractionResult;
122
+ }
123
+ // if there's a function to extract the range, use it
124
+ if (labToOhtMapper.rangeExtraction?.extractionFunc) {
125
+ rangeExtractionResult = labToOhtMapper.rangeExtraction.extractionFunc(rawData, labToOhtMapper, patientInfo, documentDate);
126
+ if (rangeExtractionResult.isRangeParsedCorrectly) {
127
+ return rangeExtractionResult;
128
+ }
129
+ }
130
+ // if there's a position and regex to extract the range, use it
131
+ if (labToOhtMapper.rangeExtraction?.extractionRegex) {
132
+ let { from, to, } = getRangeFromPositionAndRegex(labToOhtMapper.rangeExtraction, rawData);
133
+ if (labToOhtMapper.rangeExtraction?.rangePosition
134
+ && (labToOhtMapper.rangeExtraction?.extractionRegex)
135
+ && from != null // if from is 0 is valid, but fails the if condition because it's falsy
136
+ && to != null // same as from
137
+ ) {
138
+ const isRangeParsedCorrectly = !Number.isNaN(from) && !Number.isNaN(to);
139
+ return { from, to, isRangeParsedCorrectly };
140
+ }
141
+ }
142
+ return nullRangeNotParsedCorrectly;
143
+ }
144
+ function extractValueFromGreaterLowerThan(value) {
145
+ // Checks first if any greater than pattern is present
146
+ const greaterThanPatterns = (0, regexUtils_1.getGreaterThanPatterns)();
147
+ const lowerThanPatterns = (0, regexUtils_1.getLowerThanPatterns)();
148
+ value = value.toLowerCase();
149
+ for (const pattern of greaterThanPatterns) {
150
+ const match = pattern.exec(value);
151
+ if (match) {
152
+ const value = parseFloat(match?.[1].replaceAll(',', '.'));
153
+ const valueComparator = oht_types_1.MeasurementValueComparator.GREATER_THAN;
154
+ return {
155
+ extractedValue: value,
156
+ extractedValueComparator: valueComparator,
157
+ valueParsedCorrectly: !Number.isNaN(value)
158
+ };
159
+ }
160
+ }
161
+ // Checks if any lower than pattern is present
162
+ for (const pattern of lowerThanPatterns) {
163
+ const match = pattern.exec(value);
164
+ if (match) {
165
+ const value = parseFloat(match?.[1].replaceAll(',', '.'));
166
+ const valueComparator = oht_types_1.MeasurementValueComparator.LESS_THAN;
167
+ return {
168
+ extractedValue: value,
169
+ extractedValueComparator: valueComparator,
170
+ valueParsedCorrectly: !Number.isNaN(value)
171
+ };
172
+ }
173
+ }
174
+ // If no pattern is found, return the value as is and the comparator as EQUAL and isValueParsedCorrectly as false
175
+ return { extractedValue: null, extractedValueComparator: null, valueParsedCorrectly: false };
176
+ }
177
+ function parseExamValue(rawExamObj, valueExtraction, ohtBiomarker) {
178
+ let value = (0, dataUtils_1.extractValue)(rawExamObj, valueExtraction?.valuePosition);
179
+ value = valueExtraction.defaultValueExtractionFunc ? valueExtraction.defaultValueExtractionFunc(value) : value;
180
+ // If is parse float nan, the value is alphanumerical
181
+ const valueType = (0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker)
182
+ ? oht_types_1.BiomarkerValueType.NUMERICAL
183
+ : oht_types_1.BiomarkerValueType.ALPHANUMERICAL;
184
+ let alphanumericalValue = Number.isNaN(parseFloat(value))
185
+ ? value
186
+ : null;
187
+ if (valueType === oht_types_1.BiomarkerValueType.ALPHANUMERICAL
188
+ && !Number.isNaN(parseFloat(value))) {
189
+ // convert numberValue to string
190
+ alphanumericalValue = value.toString();
191
+ }
192
+ if (valueType === oht_types_1.BiomarkerValueType.NUMERICAL
193
+ && Number.isNaN(parseFloat(value))) {
194
+ // convert numberValue to string
195
+ const { extractedValue, extractedValueComparator, valueParsedCorrectly } = extractValueFromGreaterLowerThan(value);
196
+ return {
197
+ valueType,
198
+ alphanumericalValue,
199
+ numberValue: extractedValue,
200
+ valueComparator: extractedValueComparator ?? oht_types_1.MeasurementValueComparator.EQUAL,
201
+ isValueParsedCorrectly: valueParsedCorrectly
202
+ };
203
+ }
204
+ if (valueType === 'NUMERICAL') {
205
+ return {
206
+ valueType,
207
+ alphanumericalValue,
208
+ numberValue: parseFloat(value),
209
+ valueComparator: oht_types_1.MeasurementValueComparator.EQUAL,
210
+ isValueParsedCorrectly: !Number.isNaN(parseFloat(value))
211
+ };
212
+ }
213
+ if (valueType === 'ALPHANUMERICAL') {
214
+ return {
215
+ valueType,
216
+ alphanumericalValue,
217
+ numberValue: parseFloat(value),
218
+ valueComparator: oht_types_1.MeasurementValueComparator.EQUAL,
219
+ isValueParsedCorrectly: alphanumericalValue !== null
220
+ };
221
+ }
222
+ return {
223
+ valueType,
224
+ alphanumericalValue,
225
+ numberValue: null,
226
+ valueComparator: oht_types_1.MeasurementValueComparator.EQUAL,
227
+ isValueParsedCorrectly: false
228
+ };
229
+ }
230
+ function checkValueForPlausibleValues(labToOhtMapper, ohtBiomarker, unit, value, isUnitParsedCorrectly) {
231
+ if (!(0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker) && isUnitParsedCorrectly) {
232
+ return true;
233
+ }
234
+ const standardUnit = ohtBiomarker.acf.standardUnit;
235
+ const plausibleLowerValue = ohtBiomarker.acf.plausibilityRangeCheck;
236
+ const plausibleUpperValue = ohtBiomarker.acf.plausibilityRangeCheckHigh;
237
+ const biomarkerStdValueDecimals = ohtBiomarker.acf?.displayDecimals ?? 2;
238
+ if (unit !== standardUnit) {
239
+ const alternativeUnit = (Array.isArray(ohtBiomarker.acf?.alternativeUnits)
240
+ ? ohtBiomarker.acf?.alternativeUnits
241
+ : [])?.find((altUnit) => altUnit.name === unit);
242
+ if (alternativeUnit) {
243
+ const conversionFactor = alternativeUnit.conversionFactor;
244
+ value = +(value * conversionFactor).toFixed(biomarkerStdValueDecimals);
245
+ }
246
+ }
247
+ const isPlausibleValue = value >= plausibleLowerValue && value <= plausibleUpperValue;
248
+ // Log if the value is not plausible
249
+ if (!isPlausibleValue) {
250
+ logger.warn({ labToOhtMapper, value, standardUnit, plausibleLowerValue, plausibleUpperValue, filename }, `Value "${value} ${standardUnit}" not plausible "${plausibleLowerValue} to ${plausibleUpperValue}" for "${labToOhtMapper.ohtBmId}" | "${labToOhtMapper.labKey}", filename: ${filename}`);
251
+ }
252
+ return isPlausibleValue;
253
+ }
254
+ async function ohtMeasurementsExtractor(labToOhtContract, ohtCoreApiKey) {
255
+ filename = labToOhtContract.sourceFilename;
256
+ const measurements = [];
257
+ const unknownMeasurements = [];
258
+ let isReportCorrectlyParsed = true;
259
+ const allPossibleOHTBmIds = [];
260
+ [
261
+ ...Object.values(labToOhtContract.labToOhtList)
262
+ ].forEach(labToOhtMapper => {
263
+ if (labToOhtMapper.ohtBmId) {
264
+ allPossibleOHTBmIds.push(labToOhtMapper.ohtBmId);
265
+ }
266
+ });
267
+ // data to request api
268
+ const requestData = {
269
+ "biomarkerIds": allPossibleOHTBmIds,
270
+ "page": 1,
271
+ "pageSize": allPossibleOHTBmIds.length
272
+ };
273
+ // api call to ohtCore to find biomarkers.
274
+ const biomarkers = await (0, reportCreator_service_1.makeApiCallWithRetry)('post', `${OHT_CORE_URL}/v1/biomarker/biomarkers`, requestData, ohtCoreApiKey);
275
+ for (const labToOhtMapper of labToOhtContract.labToOhtList) {
276
+ if (!labToOhtMapper.rawExam) {
277
+ labToOhtContract.slackMessages.push({
278
+ type: 'ERROR',
279
+ message: `Missing rawExam for labKey: ${labToOhtMapper.labKey} filename: ${filename}`,
280
+ });
281
+ continue;
282
+ }
283
+ const rawExamObj = JSON.parse(labToOhtMapper.rawExam);
284
+ if (labToOhtMapper?.ohtBmId) {
285
+ // if BM is already in measurements, continue to the next one
286
+ if (measurements.some(measurement => measurement.biomarkerId === labToOhtMapper.ohtBmId)) {
287
+ logger.warn({ labToOhtMapper }, `Biomarker already in measurements array, should investigate, filename: ${filename}`);
288
+ labToOhtContract.slackMessages.push({
289
+ type: 'ERROR',
290
+ message: `Biomarkers Duplicated keys: [PLACEHOLDER]`,
291
+ item: `bmId:${labToOhtMapper.ohtBmId}, labKey:${labToOhtMapper.labKey}`
292
+ });
293
+ continue;
294
+ }
295
+ const ohtBiomarker = biomarkers?.data?.items.find((bm) => bm.id === labToOhtMapper.ohtBmId);
296
+ const { unit, isUnitParsedCorrectly } = extractUnit(labToOhtMapper.unitExtraction, rawExamObj, ohtBiomarker);
297
+ if (!isUnitParsedCorrectly) {
298
+ logger.warn({ labToOhtMapper }, `Unit not extracted correctly for "${labToOhtMapper.ohtBmId}|${labToOhtMapper.labKey}", filename: ${filename}`);
299
+ labToOhtContract.slackMessages.push({
300
+ type: 'ERROR',
301
+ message: `Unit not extracted correctly for keys: [PLACEHOLDER]`,
302
+ item: `bmId:${labToOhtMapper.ohtBmId}, labKey:${labToOhtMapper.labKey}`
303
+ });
304
+ }
305
+ isReportCorrectlyParsed = isReportCorrectlyParsed && isUnitParsedCorrectly;
306
+ let { valueType, alphanumericalValue, numberValue, valueComparator, isValueParsedCorrectly } = parseExamValue(rawExamObj, labToOhtMapper.valueExtraction, ohtBiomarker);
307
+ if (!isValueParsedCorrectly) {
308
+ logger.warn({ labToOhtMapper }, `Value not extracted correctly for "${labToOhtMapper.ohtBmId}|${labToOhtMapper.labKey}", filename: ${filename}`);
309
+ labToOhtContract.slackMessages.push({
310
+ type: 'ERROR',
311
+ message: `Value not extracted correctly for keys: [PLACEHOLDER]`,
312
+ item: `bmId:${labToOhtMapper.ohtBmId}, labKey:${labToOhtMapper.labKey}`
313
+ });
314
+ }
315
+ if (valueType === 'NUMERICAL') {
316
+ const isPlausibleValue = numberValue !== null && checkValueForPlausibleValues(labToOhtMapper, ohtBiomarker, unit, numberValue, isUnitParsedCorrectly);
317
+ if (!isPlausibleValue) {
318
+ logger.warn({ labToOhtMapper }, `Value [${numberValue} ${unit}] is not plausible for "${labToOhtMapper.ohtBmId}|${labToOhtMapper.labKey}", filename: ${filename}`);
319
+ labToOhtContract.slackMessages.push({
320
+ type: 'ERROR',
321
+ message: `Value is not plausible for: [PLACEHOLDER]`,
322
+ item: `bmId:${labToOhtMapper.ohtBmId}, labKey:${labToOhtMapper.labKey}, value: ${numberValue}${unit}`
323
+ });
324
+ }
325
+ isReportCorrectlyParsed = isReportCorrectlyParsed && isPlausibleValue;
326
+ }
327
+ isReportCorrectlyParsed = isReportCorrectlyParsed && isValueParsedCorrectly;
328
+ let from = null, to = null;
329
+ let isRangeParsedCorrectly = true;
330
+ if ((0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker)) {
331
+ const extractedRange = extractReferenceRanges(labToOhtMapper, rawExamObj, labToOhtContract.patientInfo, labToOhtContract.documentDate);
332
+ from = extractedRange.from ?? null;
333
+ to = extractedRange.to ?? null;
334
+ isRangeParsedCorrectly = extractedRange.isRangeParsedCorrectly;
335
+ if (!isRangeParsedCorrectly) {
336
+ logger.warn({ labToOhtMapper }, `Range not extracted correctly for "${labToOhtMapper.ohtBmId}|${labToOhtMapper.labKey}", filename: ${filename}`);
337
+ labToOhtContract.slackMessages.push({
338
+ type: 'ERROR',
339
+ message: `Range not extracted correctly for keys: [PLACEHOLDER]`,
340
+ item: `bmId:${labToOhtMapper.ohtBmId}, labKey:${labToOhtMapper.labKey}`
341
+ });
342
+ }
343
+ isReportCorrectlyParsed = isReportCorrectlyParsed && isRangeParsedCorrectly;
344
+ }
345
+ let extractedAnnotation;
346
+ if (labToOhtMapper?.referenceAsAnnotation?.use) {
347
+ extractedAnnotation = extractReferenceAnnotation(labToOhtMapper, rawExamObj, labToOhtContract.patientInfo, labToOhtContract.documentDate);
348
+ }
349
+ const material = (0, dataUtils_1.extractValue)(rawExamObj, labToOhtMapper.material);
350
+ const method = (0, dataUtils_1.extractValue)(rawExamObj, labToOhtMapper.method);
351
+ let alphaValue = !(0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker) && alphanumericalValue
352
+ ? alphanumericalValue.trim()
353
+ : null;
354
+ // adding unit for alphanumerical values as number.
355
+ if (!Number.isNaN(parseFloat(alphaValue))) {
356
+ let originalUnit = (0, dataUtils_1.extractValue)(rawExamObj, labToOhtMapper?.unitExtraction?.unitPosition);
357
+ originalUnit = originalUnit?.replaceAll(/ /g, '') ?? '';
358
+ alphaValue = alphaValue && unit?.length > 0 ? `${alphaValue} ${originalUnit}`.trim() : alphaValue;
359
+ }
360
+ let measurement = {
361
+ biomarkerId: ohtBiomarker.id,
362
+ valueType,
363
+ value: (0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker) ? numberValue : null,
364
+ alphanumericValue: alphaValue,
365
+ rangeAnnotation: labToOhtMapper?.referenceAsAnnotation?.use && extractedAnnotation ? extractedAnnotation : null,
366
+ showVisualisationIfAnnotated: !!labToOhtMapper?.referenceAsAnnotation?.use,
367
+ comparator: valueComparator ?? oht_types_1.MeasurementValueComparator.EQUAL,
368
+ minNormalValue: from,
369
+ maxNormalValue: to,
370
+ unit,
371
+ material,
372
+ method,
373
+ isDigitalizationApproved: true,
374
+ };
375
+ measurements.push(measurement);
376
+ }
377
+ else {
378
+ logger.warn(`Created an ungroupedBiomarker for id: ${labToOhtMapper.labKey}, filename: ${filename}`);
379
+ labToOhtContract.slackMessages.push({
380
+ type: 'ERROR',
381
+ message: `Created ungroupedBiomarkers for: [PLACEHOLDER]`,
382
+ item: `labKey: ${labToOhtMapper.labKey}`
383
+ });
384
+ const biomarkerName = labToOhtMapper?.unknownMeasurement?.biomarkerName ?? '';
385
+ const value = labToOhtMapper?.unknownMeasurement?.value ?? '';
386
+ const unit = labToOhtMapper?.unknownMeasurement?.unit ?? '';
387
+ const annotation = labToOhtMapper?.unknownMeasurement?.annotation ?? '';
388
+ const unknownMeasurement = {
389
+ biomarkerName: biomarkerName,
390
+ value: value,
391
+ unit: unit,
392
+ annotation: annotation
393
+ };
394
+ unknownMeasurements.push(unknownMeasurement);
395
+ }
396
+ }
397
+ return {
398
+ measurements,
399
+ unknownMeasurements,
400
+ isReportCorrectlyParsed
401
+ };
402
+ }
403
+ //# sourceMappingURL=ohtMeasurementsExtractor.service.js.map