UNPKG

@phema/cql-execution

Version:

An execution framework for the Clinical Quality Language (CQL)

1,352 lines (1,123 loc) 1.17 MB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ /* eslint-disable no-undef, */ // TODO: This file was created by bulk-decaffeinate. // Fix any style issues and re-enable lint. /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ window.cql = require('../../lib/cql'); window.executeSimpleELM = function ( elm, patientSource, valueSets, libraryName, version, executionDateTime, parameters = {} ) { let lib; if (Array.isArray(elm)) { if (elm.length > 1) { const rep = new window.cql.Repository(elm); lib = rep.resolve(libraryName, version); } else { lib = new window.cql.Library(elm[0]); } } else { lib = new window.cql.Library(elm); } const codeService = new window.cql.CodeService(valueSets); const executor = new window.cql.Executor(lib, codeService, parameters); return executor.exec(patientSource, executionDateTime); }; },{"../../lib/cql":4}],2:[function(require,module,exports){ "use strict"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var _require = require('./datatypes/datatypes'), Code = _require.Code, ValueSet = _require.ValueSet; var CodeService = /*#__PURE__*/function () { function CodeService() { var valueSetsJson = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, CodeService); this.valueSets = {}; for (var oid in valueSetsJson) { this.valueSets[oid] = {}; for (var version in valueSetsJson[oid]) { var codes = valueSetsJson[oid][version].map(function (code) { return new Code(code.code, code.system, code.version); }); this.valueSets[oid][version] = new ValueSet(oid, version, codes); } } } _createClass(CodeService, [{ key: "findValueSetsByOid", value: function findValueSetsByOid(oid) { return this.valueSets[oid] ? Object.values(this.valueSets[oid]) : []; } }, { key: "findValueSet", value: function findValueSet(oid, version) { if (version != null) { return this.valueSets[oid] != null ? this.valueSets[oid][version] : undefined; } else { var results = this.findValueSetsByOid(oid); if (results.length === 0) { return null; } else { return results.reduce(function (a, b) { if (a.version > b.version) { return a; } else { return b; } }); } } } }]); return CodeService; }(); module.exports.CodeService = CodeService; },{"./datatypes/datatypes":6}],3:[function(require,module,exports){ "use strict"; function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var DT = require('./datatypes/datatypes'); var Record = /*#__PURE__*/function () { function Record(json) { _classCallCheck(this, Record); this.json = json; this.id = this.json.id; } _createClass(Record, [{ key: "_is", value: function _is(typeSpecifier) { return this._typeHierarchy().some(function (t) { return t.type === typeSpecifier.type && t.name == typeSpecifier.name; }); } }, { key: "_typeHierarchy", value: function _typeHierarchy() { return [{ name: "{https://github.com/cqframework/cql-execution/simple}".concat(this.json.recordType), type: 'NamedTypeSpecifier' }, { name: '{https://github.com/cqframework/cql-execution/simple}Record', type: 'NamedTypeSpecifier' }, { name: '{urn:hl7-org:elm-types:r1}Any', type: 'NamedTypeSpecifier' }]; } }, { key: "_recursiveGet", value: function _recursiveGet(field) { if (field != null && field.indexOf('.') >= 0) { var _field$split = field.split('.', 2), _field$split2 = _slicedToArray(_field$split, 2), root = _field$split2[0], rest = _field$split2[1]; return new Record(this._recursiveGet(root))._recursiveGet(rest); } return this.json[field]; } }, { key: "get", value: function get(field) { // the model should return the correct type for the field. For this simple model example, // we just cheat and use the shape of the value to determine it. Real implementations should // have a more sophisticated approach var value = this._recursiveGet(field); if (typeof value === 'string' && /\d{4}-\d{2}-\d{2}(T[\d\-.]+)?/.test(value)) { return this.getDate(field); } if (value != null && _typeof(value) === 'object' && value.code != null && value.system != null) { return this.getCode(field); } if (value != null && _typeof(value) === 'object' && (value.low != null || value.high != null)) { return this.getInterval(field); } return value; } }, { key: "getId", value: function getId() { return this.id; } }, { key: "getDate", value: function getDate(field) { var val = this._recursiveGet(field); if (val != null) { return DT.DateTime.parse(val); } else { return null; } } }, { key: "getInterval", value: function getInterval(field) { var val = this._recursiveGet(field); if (val != null && _typeof(val) === 'object') { var low = val.low != null ? DT.DateTime.parse(val.low) : null; var high = val.high != null ? DT.DateTime.parse(val.high) : null; return new DT.Interval(low, high); } } }, { key: "getDateOrInterval", value: function getDateOrInterval(field) { var val = this._recursiveGet(field); if (val != null && _typeof(val) === 'object') { return this.getInterval(field); } else { return this.getDate(field); } } }, { key: "getCode", value: function getCode(field) { var val = this._recursiveGet(field); if (val != null && _typeof(val) === 'object') { return new DT.Code(val.code, val.system, val.version); } } }]); return Record; }(); var Patient = /*#__PURE__*/function (_Record) { _inherits(Patient, _Record); var _super = _createSuper(Patient); function Patient(json) { var _this; _classCallCheck(this, Patient); _this = _super.call(this, json); _this.name = json.name; _this.gender = json.gender; _this.birthDate = json.birthDate != null ? DT.DateTime.parse(json.birthDate) : undefined; _this.records = {}; (json.records || []).forEach(function (r) { if (_this.records[r.recordType] == null) { _this.records[r.recordType] = []; } _this.records[r.recordType].push(new Record(r)); }); return _this; } _createClass(Patient, [{ key: "findRecords", value: function findRecords(profile) { if (profile == null) { return []; } var recordType = profile.match(/(\{https:\/\/github\.com\/cqframework\/cql-execution\/simple\})?(.*)/)[2]; if (recordType === 'Patient') { return [this]; } else { return this.records[recordType] || []; } } }]); return Patient; }(Record); var PatientSource = /*#__PURE__*/function () { function PatientSource(patients) { _classCallCheck(this, PatientSource); this.patients = patients; this.nextPatient(); } _createClass(PatientSource, [{ key: "currentPatient", value: function currentPatient() { return this.current; } }, { key: "nextPatient", value: function nextPatient() { var currentJSON = this.patients.shift(); this.current = currentJSON ? new Patient(currentJSON) : undefined; return this.current; } }]); return PatientSource; }(); module.exports.Patient = Patient; module.exports.PatientSource = PatientSource; },{"./datatypes/datatypes":6}],4:[function(require,module,exports){ "use strict"; var library = require('./elm/library'); var expression = require('./elm/expression'); var repository = require('./runtime/repository'); var context = require('./runtime/context'); var exec = require('./runtime/executor'); var results = require('./runtime/results'); var datatypes = require('./datatypes/datatypes'); var patient = require('./cql-patient'); var codeservice = require('./cql-code-service'); // Library-related classes module.exports.Library = library.Library; module.exports.Repository = repository.Repository; module.exports.Expression = expression.Expression; // Execution-related classes module.exports.Context = context.Context; module.exports.Executor = exec.Executor; module.exports.PatientContext = context.PatientContext; module.exports.UnfilteredContext = context.UnfilteredContext; module.exports.Results = results.Results; // PatientSource-related classes module.exports.Patient = patient.Patient; module.exports.PatientSource = patient.PatientSource; // TerminologyService-related classes module.exports.CodeService = codeservice.CodeService; // DataType classes module.exports.Code = datatypes.Code; module.exports.CodeSystem = datatypes.CodeSystem; module.exports.Concept = datatypes.Concept; module.exports.Date = datatypes.Date; module.exports.DateTime = datatypes.DateTime; module.exports.Interval = datatypes.Interval; module.exports.Quantity = datatypes.Quantity; module.exports.Ratio = datatypes.Ratio; module.exports.ValueSet = datatypes.ValueSet; },{"./cql-code-service":2,"./cql-patient":3,"./datatypes/datatypes":6,"./elm/expression":22,"./elm/library":27,"./runtime/context":41,"./runtime/executor":42,"./runtime/repository":43,"./runtime/results":44}],5:[function(require,module,exports){ "use strict"; function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var _require = require('../util/util'), typeIsArray = _require.typeIsArray; var Code = /*#__PURE__*/function () { function Code(code, system, version, display) { _classCallCheck(this, Code); this.code = code; this.system = system; this.version = version; this.display = display; } _createClass(Code, [{ key: "isCode", get: function get() { return true; } }, { key: "hasMatch", value: function hasMatch(code) { if (typeof code === 'string') { // the specific behavior for this is not in the specification. Matching codesystem behavior. return code === this.code; } else { return codesInList(toCodeList(code), [this]); } } }]); return Code; }(); var Concept = /*#__PURE__*/function () { function Concept(codes, display) { _classCallCheck(this, Concept); this.codes = codes || []; this.display = display; } _createClass(Concept, [{ key: "isConcept", get: function get() { return true; } }, { key: "hasMatch", value: function hasMatch(code) { return codesInList(toCodeList(code), this.codes); } }]); return Concept; }(); var ValueSet = /*#__PURE__*/function () { function ValueSet(oid, version, codes) { _classCallCheck(this, ValueSet); this.oid = oid; this.version = version; this.codes = codes || []; } _createClass(ValueSet, [{ key: "isValueSet", get: function get() { return true; } }, { key: "hasMatch", value: function hasMatch(code) { var codesList = toCodeList(code); // InValueSet String Overload if (codesList.length === 1 && typeof codesList[0] === 'string') { var matchFound = false; var multipleCodeSystemsExist = false; var _iterator = _createForOfIteratorHelper(this.codes), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var codeItem = _step.value; // Confirm all code systems match if (codeItem.system !== this.codes[0].system) { multipleCodeSystemsExist = true; } if (codeItem.code === codesList[0]) { matchFound = true; } if (multipleCodeSystemsExist && matchFound) { throw new Error('In (valueset) is ambiguous -- multiple codes with multiple code systems exist in value set.'); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return matchFound; } else { return codesInList(codesList, this.codes); } } }]); return ValueSet; }(); function toCodeList(c) { if (c == null) { return []; } else if (typeIsArray(c)) { var list = []; var _iterator2 = _createForOfIteratorHelper(c), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var c2 = _step2.value; list = list.concat(toCodeList(c2)); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return list; } else if (typeIsArray(c.codes)) { return c.codes; } else { return [c]; } } function codesInList(cl1, cl2) { // test each code in c1 against each code in c2 looking for a match return cl1.some(function (c1) { return cl2.some(function (c2) { // only the left argument (cl1) can contain strings. cl2 will only contain codes. if (typeof c1 === 'string') { // for "string in codesystem" this should compare the string to // the code's "code" field according to the specification. return c1 === c2.code; } else { return codesMatch(c1, c2); } }); }); } function codesMatch(code1, code2) { return code1.code === code2.code && code1.system === code2.system; } var CodeSystem = function CodeSystem(id, version) { _classCallCheck(this, CodeSystem); this.id = id; this.version = version; }; module.exports = { Code: Code, Concept: Concept, ValueSet: ValueSet, CodeSystem: CodeSystem }; },{"../util/util":48}],6:[function(require,module,exports){ "use strict"; var logic = require('./logic'); var clinical = require('./clinical'); var uncertainty = require('./uncertainty'); var datetime = require('./datetime'); var interval = require('./interval'); var quantity = require('./quantity'); var ratio = require('./ratio'); var libs = [logic, clinical, uncertainty, datetime, interval, quantity, ratio]; for (var _i = 0, _libs = libs; _i < _libs.length; _i++) { var lib = _libs[_i]; for (var _i2 = 0, _Object$keys = Object.keys(lib); _i2 < _Object$keys.length; _i2++) { var element = _Object$keys[_i2]; module.exports[element] = lib[element]; } } },{"./clinical":5,"./datetime":7,"./interval":9,"./logic":10,"./quantity":11,"./ratio":12,"./uncertainty":13}],7:[function(require,module,exports){ "use strict"; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var _require = require('./uncertainty'), Uncertainty = _require.Uncertainty; var _require2 = require('../util/util'), jsDate = _require2.jsDate, normalizeMillisecondsField = _require2.normalizeMillisecondsField, normalizeMillisecondsFieldInString = _require2.normalizeMillisecondsFieldInString; var luxon = require('luxon'); // It's easiest and most performant to organize formats by length of the supported strings. // This way we can test strings only against the formats that have a chance of working. // NOTE: Formats use Luxon formats, documented here: https://moment.github.io/luxon/docs/manual/parsing.html#table-of-tokens var LENGTH_TO_DATE_FORMAT_MAP = function () { var ltdfMap = new Map(); ltdfMap.set(4, 'yyyy'); ltdfMap.set(7, 'yyyy-MM'); ltdfMap.set(10, 'yyyy-MM-dd'); return ltdfMap; }(); var LENGTH_TO_DATETIME_FORMATS_MAP = function () { var formats = { yyyy: '2012', 'yyyy-MM': '2012-01', 'yyyy-MM-dd': '2012-01-31', "yyyy-MM-dd'T''Z'": '2012-01-31TZ', "yyyy-MM-dd'T'ZZ": '2012-01-31T-04:00', "yyyy-MM-dd'T'HH": '2012-01-31T12', "yyyy-MM-dd'T'HH'Z'": '2012-01-31T12Z', "yyyy-MM-dd'T'HHZZ": '2012-01-31T12-04:00', "yyyy-MM-dd'T'HH:mm": '2012-01-31T12:30', "yyyy-MM-dd'T'HH:mm'Z'": '2012-01-31T12:30Z', "yyyy-MM-dd'T'HH:mmZZ": '2012-01-31T12:30-04:00', "yyyy-MM-dd'T'HH:mm:ss": '2012-01-31T12:30:59', "yyyy-MM-dd'T'HH:mm:ss'Z'": '2012-01-31T12:30:59Z', "yyyy-MM-dd'T'HH:mm:ssZZ": '2012-01-31T12:30:59-04:00', "yyyy-MM-dd'T'HH:mm:ss.SSS": '2012-01-31T12:30:59.000', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'": '2012-01-31T12:30:59.000Z', "yyyy-MM-dd'T'HH:mm:ss.SSSZZ": '2012-01-31T12:30:59.000-04:00' }; var ltdtfMap = new Map(); Object.keys(formats).forEach(function (k) { var example = formats[k]; if (!ltdtfMap.has(example.length)) { ltdtfMap.set(example.length, [k]); } else { ltdtfMap.get(example.length).push(k); } }); return ltdtfMap; }(); function wholeLuxonDuration(duration, unit) { var value = duration.get(unit); return value >= 0 ? Math.floor(value) : Math.ceil(value); } function truncateLuxonDateTime(luxonDT, unit) { // Truncating by week (to the previous Sunday) requires different logic than the rest if (unit === DateTime.Unit.WEEK) { // Sunday is ISO weekday 7 if (luxonDT.weekday !== 7) { luxonDT = luxonDT.set({ weekday: 7 }).minus({ weeks: 1 }); } unit = DateTime.Unit.DAY; } return luxonDT.startOf(unit); } var DateTime = /*#__PURE__*/function () { function DateTime() { var year = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var month = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var day = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var hour = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; var minute = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; var second = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null; var millisecond = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null; var timezoneOffset = arguments.length > 7 ? arguments[7] : undefined; _classCallCheck(this, DateTime); // from the spec: If no timezone is specified, the timezone of the evaluation request timestamp is used. // NOTE: timezoneOffset will be explicitly null for the Time overload, whereas // it will be undefined if simply unspecified this.year = year; this.month = month; this.day = day; this.hour = hour; this.minute = minute; this.second = second; this.millisecond = millisecond; this.timezoneOffset = timezoneOffset; if (this.timezoneOffset === undefined) { this.timezoneOffset = new jsDate().getTimezoneOffset() / 60 * -1; } } _createClass(DateTime, [{ key: "isDateTime", get: function get() { return true; } }, { key: "copy", value: function copy() { return new DateTime(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond, this.timezoneOffset); } }, { key: "successor", value: function successor() { if (this.millisecond != null) { return this.add(1, DateTime.Unit.MILLISECOND); } else if (this.second != null) { return this.add(1, DateTime.Unit.SECOND); } else if (this.minute != null) { return this.add(1, DateTime.Unit.MINUTE); } else if (this.hour != null) { return this.add(1, DateTime.Unit.HOUR); } else if (this.day != null) { return this.add(1, DateTime.Unit.DAY); } else if (this.month != null) { return this.add(1, DateTime.Unit.MONTH); } else if (this.year != null) { return this.add(1, DateTime.Unit.YEAR); } } }, { key: "predecessor", value: function predecessor() { if (this.millisecond != null) { return this.add(-1, DateTime.Unit.MILLISECOND); } else if (this.second != null) { return this.add(-1, DateTime.Unit.SECOND); } else if (this.minute != null) { return this.add(-1, DateTime.Unit.MINUTE); } else if (this.hour != null) { return this.add(-1, DateTime.Unit.HOUR); } else if (this.day != null) { return this.add(-1, DateTime.Unit.DAY); } else if (this.month != null) { return this.add(-1, DateTime.Unit.MONTH); } else if (this.year != null) { return this.add(-1, DateTime.Unit.YEAR); } } }, { key: "convertToTimezoneOffset", value: function convertToTimezoneOffset() { var timezoneOffset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var shiftedLuxonDT = this.toLuxonDateTime().setZone(luxon.FixedOffsetZone.instance(timezoneOffset * 60)); var shiftedDT = DateTime.fromLuxonDateTime(shiftedLuxonDT); return shiftedDT.reducedPrecision(this.getPrecision()); } }, { key: "differenceBetween", value: function differenceBetween(other, unitField) { other = this._implicitlyConvert(other); if (other == null || !other.isDateTime) { return null; } // According to CQL spec: // * "Difference calculations are performed by truncating the datetime values at the next precision, // and then performing the corresponding duration calculation on the truncated values." // * "When difference is calculated for hours or finer units, timezone offsets should be normalized // prior to truncation to correctly consider real (actual elapsed) time. When difference is calculated // for days or coarser units, however, the time components (including timezone offset) should be truncated // without normalization to correctly reflect the difference in calendar days, months, and years." var a = this.toLuxonUncertainty(); var b = other.toLuxonUncertainty(); // If unit is days or above, reset all the DateTimes to UTC since TZ offset should not be considered; // Otherwise, we don't actually have to "normalize" to a common TZ because Luxon takes TZ into account. if ([DateTime.Unit.YEAR, DateTime.Unit.MONTH, DateTime.Unit.WEEK, DateTime.Unit.DAY].includes(unitField)) { a.low = a.low.toUTC(0, { keepLocalTime: true }); a.high = a.high.toUTC(0, { keepLocalTime: true }); b.low = b.low.toUTC(0, { keepLocalTime: true }); b.high = b.high.toUTC(0, { keepLocalTime: true }); } // Truncate all dates at precision below specified unit a.low = truncateLuxonDateTime(a.low, unitField); a.high = truncateLuxonDateTime(a.high, unitField); b.low = truncateLuxonDateTime(b.low, unitField); b.high = truncateLuxonDateTime(b.high, unitField); // Return the duration based on the normalize and truncated values return new Uncertainty(wholeLuxonDuration(b.low.diff(a.high, unitField), unitField), wholeLuxonDuration(b.high.diff(a.low, unitField), unitField)); } }, { key: "durationBetween", value: function durationBetween(other, unitField) { other = this._implicitlyConvert(other); if (other == null || !other.isDateTime) { return null; } var a = this.toLuxonUncertainty(); var b = other.toLuxonUncertainty(); return new Uncertainty(wholeLuxonDuration(b.low.diff(a.high, unitField), unitField), wholeLuxonDuration(b.high.diff(a.low, unitField), unitField)); } }, { key: "isUTC", value: function isUTC() { // A timezoneOffset of 0 indicates UTC time. return !this.timezoneOffset; } }, { key: "getPrecision", value: function getPrecision() { var result = null; if (this.year != null) { result = DateTime.Unit.YEAR; } else { return result; } if (this.month != null) { result = DateTime.Unit.MONTH; } else { return result; } if (this.day != null) { result = DateTime.Unit.DAY; } else { return result; } if (this.hour != null) { result = DateTime.Unit.HOUR; } else { return result; } if (this.minute != null) { result = DateTime.Unit.MINUTE; } else { return result; } if (this.second != null) { result = DateTime.Unit.SECOND; } else { return result; } if (this.millisecond != null) { result = DateTime.Unit.MILLISECOND; } return result; } }, { key: "toLuxonDateTime", value: function toLuxonDateTime() { var offsetMins = this.timezoneOffset != null ? this.timezoneOffset * 60 : new jsDate().getTimezoneOffset() * -1; return luxon.DateTime.fromObject({ year: this.year, month: this.month, day: this.day, hour: this.hour, minute: this.minute, second: this.second, millisecond: this.millisecond, zone: luxon.FixedOffsetZone.instance(offsetMins) }); } }, { key: "toLuxonUncertainty", value: function toLuxonUncertainty() { var low = this.toLuxonDateTime(); var high = low.endOf(this.getPrecision()); return new Uncertainty(low, high); } }, { key: "toJSDate", value: function toJSDate() { var ignoreTimezone = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var luxonDT = this.toLuxonDateTime(); // I don't know if anyone is using "ignoreTimezone" anymore (we aren't), but just in case if (ignoreTimezone) { var offset = new jsDate().getTimezoneOffset() * -1; luxonDT = luxonDT.setZone(luxon.FixedOffsetZone.instance(offset), { keepLocalTime: true }); } return luxonDT.toJSDate(); } }, { key: "toJSON", value: function toJSON() { return this.toString(); } }, { key: "_pad", value: function _pad(num) { return String('0' + num).slice(-2); } }, { key: "toString", value: function toString() { if (this.isTime()) { return this.toStringTime(); } else { return this.toStringDateTime(); } } }, { key: "toStringTime", value: function toStringTime() { var str = ''; if (this.hour != null) { str += this._pad(this.hour); if (this.minute != null) { str += ':' + this._pad(this.minute); if (this.second != null) { str += ':' + this._pad(this.second); if (this.millisecond != null) { str += '.' + String('00' + this.millisecond).slice(-3); } } } } return str; } }, { key: "toStringDateTime", value: function toStringDateTime() { var str = ''; if (this.year != null) { str += this.year; if (this.month != null) { str += '-' + this._pad(this.month); if (this.day != null) { str += '-' + this._pad(this.day); if (this.hour != null) { str += 'T' + this._pad(this.hour); if (this.minute != null) { str += ':' + this._pad(this.minute); if (this.second != null) { str += ':' + this._pad(this.second); if (this.millisecond != null) { str += '.' + String('00' + this.millisecond).slice(-3); } } } } } } } if (str.indexOf('T') !== -1 && this.timezoneOffset != null) { str += this.timezoneOffset < 0 ? '-' : '+'; var offsetHours = Math.floor(Math.abs(this.timezoneOffset)); str += this._pad(offsetHours); var offsetMin = (Math.abs(this.timezoneOffset) - offsetHours) * 60; str += ':' + this._pad(offsetMin); } return str; } }, { key: "getDateTime", value: function getDateTime() { return this; } }, { key: "getDate", value: function getDate() { return new _Date(this.year, this.month, this.day); } }, { key: "getTime", value: function getTime() { // Times no longer have timezoneOffets, so we must explicitly set it to null return new DateTime(0, 1, 1, this.hour, this.minute, this.second, this.millisecond, null); } }, { key: "isTime", value: function isTime() { return this.year === 0 && this.month === 1 && this.day === 1; } }, { key: "_implicitlyConvert", value: function _implicitlyConvert(other) { if (other != null && other.isDate) { return other.getDateTime(); } return other; } }, { key: "reducedPrecision", value: function reducedPrecision() { var unitField = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DateTime.Unit.MILLISECOND; var reduced = this.copy(); if (unitField !== DateTime.Unit.MILLISECOND) { var fieldIndex = DateTime.FIELDS.indexOf(unitField); var fieldsToRemove = DateTime.FIELDS.slice(fieldIndex + 1); var _iterator = _createForOfIteratorHelper(fieldsToRemove), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var field = _step.value; reduced[field] = null; } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } return reduced; } }], [{ key: "parse", value: function parse(string) { if (string === null) { return null; } var matches = /(\d{4})(-(\d{2}))?(-(\d{2}))?(T((\d{2})(:(\d{2})(:(\d{2})(\.(\d+))?)?)?)?(Z|(([+-])(\d{2})(:?(\d{2}))?))?)?/.exec(string); if (matches == null) { return null; } var years = matches[1]; var months = matches[3]; var days = matches[5]; var hours = matches[8]; var minutes = matches[10]; var seconds = matches[12]; var milliseconds = matches[14]; if (milliseconds != null) { milliseconds = normalizeMillisecondsField(milliseconds); } if (milliseconds != null) { string = normalizeMillisecondsFieldInString(string, matches[14]); } if (!isValidDateTimeStringFormat(string)) { return null; } // convert the args to integers var args = [years, months, days, hours, minutes, seconds, milliseconds].map(function (arg) { return arg != null ? parseInt(arg) : arg; }); // convert timezone offset to decimal and add it to arguments if (matches[18] != null) { var num = parseInt(matches[18]) + (matches[20] != null ? parseInt(matches[20]) / 60 : 0); args.push(matches[17] === '+' ? num : num * -1); } else if (matches[15] === 'Z') { args.push(0); } return _construct(DateTime, _toConsumableArray(args)); } }, { key: "fromJSDate", value: function fromJSDate(date, timezoneOffset) { //This is from a JS Date, not a CQL Date if (date instanceof DateTime) { return date; } if (timezoneOffset != null) { date = new jsDate(date.getTime() + timezoneOffset * 60 * 60 * 1000); return new DateTime(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds(), timezoneOffset); } else { return new DateTime(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()); } } }, { key: "fromLuxonDateTime", value: function fromLuxonDateTime(luxonDT) { if (luxonDT instanceof DateTime) { return luxonDT; } return new DateTime(luxonDT.year, luxonDT.month, luxonDT.day, luxonDT.hour, luxonDT.minute, luxonDT.second, luxonDT.millisecond, luxonDT.offset / 60); } }]); return DateTime; }(); DateTime.Unit = { YEAR: 'year', MONTH: 'month', WEEK: 'week', DAY: 'day', HOUR: 'hour', MINUTE: 'minute', SECOND: 'second', MILLISECOND: 'millisecond' }; DateTime.FIELDS = [DateTime.Unit.YEAR, DateTime.Unit.MONTH, DateTime.Unit.DAY, DateTime.Unit.HOUR, DateTime.Unit.MINUTE, DateTime.Unit.SECOND, DateTime.Unit.MILLISECOND]; var _Date = /*#__PURE__*/function () { function _Date() { var year = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var month = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var day = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; _classCallCheck(this, _Date); this.year = year; this.month = month; this.day = day; } _createClass(_Date, [{ key: "isDate", get: function get() { return true; } }, { key: "copy", value: function copy() { return new _Date(this.year, this.month, this.day); } }, { key: "successor", value: function successor() { if (this.day != null) { return this.add(1, _Date.Unit.DAY); } else if (this.month != null) { return this.add(1, _Date.Unit.MONTH); } else if (this.year != null) { return this.add(1, _Date.Unit.YEAR); } } }, { key: "predecessor", value: function predecessor() { if (this.day != null) { return this.add(-1, _Date.Unit.DAY); } else if (this.month != null) { return this.add(-1, _Date.Unit.MONTH); } else if (this.year != null) { return this.add(-1, _Date.Unit.YEAR); } } }, { key: "differenceBetween", value: function differenceBetween(other, unitField) { if (other != null && other.isDateTime) { return this.getDateTime().differenceBetween(other, unitField); } if (other == null || !other.isDate) { return null; } // According to CQL spec: // * "Difference calculations are performed by truncating the datetime values at the next precision, // and then performing the corresponding duration calculation on the truncated values." var a = this.toLuxonUncertainty(); var b = other.toLuxonUncertainty(); // Truncate all dates at precision below specified unit a.low = truncateLuxonDateTime(a.low, unitField); a.high = truncateLuxonDateTime(a.high, unitField); b.low = truncateLuxonDateTime(b.low, unitField); b.high = truncateLuxonDateTime(b.high, unitField); // Return the duration based on the normalize and truncated values return new Uncertainty(wholeLuxonDuration(b.low.diff(a.high, unitField), unitField), wholeLuxonDuration(b.high.diff(a.low, unitField), unitField)); } }, { key: "durationBetween", value: function durationBetween(other, unitField) { if (other != null && other.isDateTime) { return this.getDateTime().durationBetween(other, unitField); } if (other == null || !other.isDate) { return null; } var a = this.toLuxonUncertainty(); var b = other.toLuxonUncertainty(); return new Uncertainty(wholeLuxonDuration(b.low.diff(a.high, unitField), unitField), wholeLuxonDuration(b.high.diff(a.low, unitField), unitField)); } }, { key: "getPrecision", value: function getPrecision() { var result = null; if (this.year != null) { result = _Date.Unit.YEAR; } else { return result; } if (this.month != null) { result = _Date.Unit.MONTH; } else { return result; } if (this.day != null) { result = _Date.Unit.DAY; } else { return result; } return result; } }, { key: "toLuxonDateTime", value: function toLuxonDateTime() { return luxon.DateTime.fromObject({ year: this.year, month: this.month, day: this.day, zone: luxon.FixedOffsetZone.utcInstance }); } }, { key: "toLuxonUncertainty", value: function toLuxonUncertainty() { var low = this.toLuxonDateTime(); var high = low.endOf(this.getPrecision()).startOf('day'); // Date type is always at T00:00:00.0 return new Uncertainty(low, high); } }, { key: "toJSDate", value: function toJSDate() { var _ref = [this.year, this.month != null ? this.month - 1 : 0, this.day != null ? this.day : 1], y = _ref[0], mo = _ref[1], d = _ref[2]; return new jsDate(y, mo, d); } }, { key: "toJSON", value: function toJSON() { return this.toString(); } }, { key: "toString", value: function toString() { var str = ''; if (this.year != null) { str += this.year.toString(); if (this.month != null) { str += '-' + this.month.toString().padStart(2, '0'); if (this.day != null) { str += '-' + this.day.toString().padStart(2, '0'); } } } return str; } }, { key: "getDateTime", value: function getDateTime() { // from the spec: the result will be a DateTime with the time components set to zero, // except for the timezone offset, which will be set to the timezone offset of the evaluation // request timestamp. (this last part is acheived by just not passing in timezone offset) if (this.year != null && this.month != null && this.day != null) { return new DateTime(this.year, this.month, this.day, 0, 0, 0, 0); // from spec: no component may be specified at a precision below an unspecified precision. // For example, hour may be null, but if it is, minute, second, and millisecond must all be null as well. } else { return new DateTime(this.year, this.month, this.day); } } }, { key: "reducedPrecision", value: function reducedPrecision() { var unitField = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _Date.Unit.DAY; var reduced = this.copy(); if (unitField !== _Date.Unit.DAY) { var fieldIndex = _Date.FIELDS.indexOf(unitField); var fieldsToRemove = _Date.FIELDS.slice(fieldIndex + 1); var _iterator2 = _createForOfIteratorHelper(fieldsToRemove),