- Mirth Connect to be installed locally
- VSCode task set up with paths pointed to the local Mirth instance (provided file are for default Windows locations)
vs_mirth.jsshould be placed in the location specified in line 14 of the build task (arg 4)- Executed file has to be based on a saved file NOTE: Changes don't have to be saved to execute as the build task will save the file if needed.
Last active
November 6, 2025 01:48
-
-
Save mhokanson/1ba83e6913817358c043b96e205e3499 to your computer and use it in GitHub Desktop.
Nextgen/Mirth Connect testing in VSCode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var msgString = "MSH|^~\\&|system1|TEST|system2|UHN|200105231927||ADT^A01^ADT_A01|22139243|P|2.4\n" + | |
| "EVN|A01|200105231927|\n" + | |
| "PID||9999999999^^|2216506^||Duck^Donald^^^MR.^MR.||19720227|M|||123 Foo ST.^^TORONTO^ON^M6G 3E6^CA^H^~123 Foo ST.^^TORONTO^ON^M6G 3E6^CA^M^|1811|(416)111-1111||E^ ENGLISH|S| PATIENT DID NOT INDICATE|211004554^||||||||||||\n" + | |
| "PV1|||ZFAST TRACK^WAITING^13|E^EMERGENCY||369^6^13^U EM EMERGENCY DEPARTMENT^ZFAST TRACK WAITING^FT WAIT 13^FTWAIT13^FT WAITING^FTWAIT13|^MOUSE^MICKEY^M^^DR.^MD|||SUR||||||||I|211004554^||||||||||||||||||||W|||||200105231927|||||\n" + | |
| "PV2||F|^R/O APPENDICIAL ABSCESS|||||||||||||||||||||||||\n" + | |
| "IN1|1||001001| OHIP||||||||||||^^^^^|||^^^^^^M^|||||||||||||||||||||||||^^^^^^M^|||||\n" + | |
| "ACC|\n" | |
| var msg = new XML(SerializerFactory.getSerializer('HL7V2').toXML(msgString)) | |
| logger.info(msg['MSH']['MSH.4']['MSH.4.1'].toString()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| // See https://go.microsoft.com/fwlink/?LinkId=733558 | |
| // for the documentation about the tasks.json format | |
| "version": "2.0.0", | |
| "tasks": [ | |
| { | |
| "label": "Run in Rhino shell", | |
| "type": "process", | |
| "command": "java", | |
| "args": [ | |
| "org.mozilla.javascript.tools.shell.Main", | |
| "-version", | |
| "200", | |
| "${env:USERPROFILE}/AppData/Roaming/vs_mirth/vs_mirth.js", | |
| "${file}" | |
| ], | |
| // "options": { | |
| // "env": { | |
| // "CLASSPATH": "./*:./commons/*:./database/*:./donkey/*:./javax/*:./jersey/*:./jetty/*:./jms/*:./swagger/*:./javax/jaxb/*:./javax/jaxws/*:./javax/jaxb/ext/*:./javax/jaxws/ext/*:./jersey/ext/*:./jetty/jsp/*:./swagger/ext/*:./custom-lib/*:../extensions/dashboardstatus/*:../extensions/datapruner/*:../extensions/datatype-delimited/*:../extensions/datatype-dicom/*:../extensions/datatype-edi/*:../extensions/datatype-hl7v2/*:../extensions/datatype-hl7v3/*:../extensions/datatype-json/*:../extensions/datatype-ncpdp/*:../extensions/datatype-raw/*:../extensions/datatype-xml/*:../extensions/destinationsetfilter/*:../extensions/dicom/*:../extensions/dicomviewer/*:../extensions/directoryresource/*:../extensions/doc/*:../extensions/extensionmanager/*:../extensions/file/*:../extensions/globalmapviewer/*:../extensions/http/*:../extensions/httpauth/*:../extensions/imageviewer/*:../extensions/javascriptrule/*:../extensions/javascriptstep/*:../extensions/jdbc/*:../extensions/jms/*:../extensions/js/*:../extensions/mapper/*:../extensions/messagebuilder/*:../extensions/mllpmode/*:../extensions/pdfviewer/*:../extensions/rulebuilder/*:../extensions/scriptfilerule/*:../extensions/scriptfilestep/*:../extensions/serverlog/*:../extensions/smtp/*:../extensions/tcp/*:../extensions/textviewer/*:../extensions/vm/*:../extensions/ws/*:../extensions/xsltstep/*:../extensions/dicom/lib/*:../extensions/dicomviewer/lib/*:../extensions/doc/lib/*:../extensions/file/lib/*:../extensions/httpauth/src/*:../extensions/pdfviewer/lib/*:../extensions/ws/lib/*" | |
| // }, | |
| // "cwd": "$HOME/mirth/release/3.7.1/server-lib" | |
| // }, | |
| "windows": { | |
| "options": { | |
| "env": { | |
| "CLASSPATH": ".\\*;.\\commons\\*;.\\database\\*;.\\donkey\\*;.\\javax\\*;.\\jersey\\*;.\\jetty\\*;.\\jms\\*;.\\swagger\\*;.\\javax\\jaxb\\*;.\\javax\\jaxws\\*;.\\javax\\jaxb\\ext\\*;.\\javax\\jaxws\\ext\\*;.\\jersey\\ext\\*;.\\jetty\\jsp\\*;.\\swagger\\ext\\*;.\\custom-lib\\*;..\\extensions\\dashboardstatus\\*;..\\extensions\\datapruner\\*;..\\extensions\\datatype-delimited\\*;..\\extensions\\datatype-dicom\\*;..\\extensions\\datatype-edi\\*;..\\extensions\\datatype-hl7v2\\*;..\\extensions\\datatype-hl7v3\\*;..\\extensions\\datatype-json\\*;..\\extensions\\datatype-ncpdp\\*;..\\extensions\\datatype-raw\\*;..\\extensions\\datatype-xml\\*;..\\extensions\\destinationsetfilter\\*;..\\extensions\\dicom\\*;..\\extensions\\dicomviewer\\*;..\\extensions\\directoryresource\\*;..\\extensions\\doc\\*;..\\extensions\\extensionmanager\\*;..\\extensions\\file\\*;..\\extensions\\globalmapviewer\\*;..\\extensions\\http\\*;..\\extensions\\httpauth\\*;..\\extensions\\imageviewer\\*;..\\extensions\\javascriptrule\\*;..\\extensions\\javascriptstep\\*;..\\extensions\\jdbc\\*;..\\extensions\\jms\\*;..\\extensions\\js\\*;..\\extensions\\mapper\\*;..\\extensions\\messagebuilder\\*;..\\extensions\\mllpmode\\*;..\\extensions\\pdfviewer\\*;..\\extensions\\rulebuilder\\*;..\\extensions\\scriptfilerule\\*;..\\extensions\\scriptfilestep\\*;..\\extensions\\serverlog\\*;..\\extensions\\smtp\\*;..\\extensions\\tcp\\*;..\\extensions\\textviewer\\*;..\\extensions\\vm\\*;..\\extensions\\ws\\*;..\\extensions\\xsltstep\\*;..\\extensions\\dicom\\lib\\*;..\\extensions\\dicomviewer\\lib\\*;..\\extensions\\doc\\lib\\*;..\\extensions\\file\\lib\\*;..\\extensions\\httpauth\\src\\*;..\\extensions\\pdfviewer\\lib\\*;..\\extensions\\ws\\lib\\*;..\\client-lib\\userutil-sources.jar;C:\\Program Files\\Mirth Connect\\server-lib\\hapi\\*;" | |
| }, | |
| "cwd": "C:\\Program Files\\Mirth Connect\\server-lib" | |
| } | |
| }, | |
| "group": { | |
| "kind": "build", | |
| "isDefault": true | |
| } | |
| } | |
| ] | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| importPackage(com.mirth.connect.server.userutil) | |
| /* | |
| * Some of the functions in this module are Copyright (c) Mirth Corporation and are | |
| * published under the terms of the MPL. | |
| * | |
| * Original source available here: | |
| * https://github.com/nextgenhealthcare/connect/blob/3.8.x/server/src/com/mirth/connect/server/builders/JavaScriptBuilder.java | |
| */ | |
| // Written by Tony Germano and found at https://forums.mirthproject.io/forum/mirth-connect/support/18382-run-javascript-in-channel-context-outside-of-mirth?p=101745#post101745 | |
| var SerializerFactory = (function () { | |
| var datatypes = com.mirth.connect.plugins.datatypes; | |
| var dataPluginClasses = [ | |
| datatypes.delimited.DelimitedDataTypeServerPlugin, | |
| datatypes.dicom.DICOMDataTypeServerPlugin, | |
| datatypes.edi.EDIDataTypeServerPlugin, | |
| datatypes.hl7v2.HL7v2DataTypeServerPlugin, | |
| datatypes.hl7v3.HL7V3DataTypeServerPlugin, | |
| datatypes.json.JSONDataTypeServerPlugin, | |
| datatypes.ncpdp.NCPDPDataTypeServerPlugin, | |
| datatypes.xml.XMLDataTypeServerPlugin | |
| ]; | |
| var dataPlugins = new org.apache.commons.collections4.map.CaseInsensitiveMap( | |
| dataPluginClasses.reduce(function (obj, javaClass) { | |
| try { | |
| var instance = new javaClass(); | |
| obj[instance.getPluginPointName()] = instance; | |
| } | |
| catch (e) { } | |
| return obj; | |
| }, {}) | |
| ); | |
| function addDataTypeServerPlugin(javaClass) { | |
| try { | |
| var instance = new javaClass(); | |
| dataPlugins.put(instance.getPluginPointName(), instance); | |
| } | |
| catch (e) { } | |
| } | |
| function getSerializer(dataType, serializationPropertiesMap, deserializationPropertiesMap) { | |
| return (arguments.length === 1) | |
| ? _getSerializer(dataType, null, null) | |
| : _getSerializer(dataType, serializationPropertiesMap, deserializationPropertiesMap); | |
| function _getSerializer(dataType, serializationPropertiesMap, deserializationPropertiesMap) { | |
| var plugin = dataPlugins.get(dataType); | |
| if (plugin != null) { | |
| if (serializationPropertiesMap == null) { | |
| serializationPropertiesMap = getDefaultSerializationProperties(dataType); | |
| } | |
| if (deserializationPropertiesMap == null) { | |
| deserializationPropertiesMap = getDefaultDeserializationProperties(dataType); | |
| } | |
| var properties = plugin.getDefaultProperties().getSerializerProperties(); | |
| if (properties.getSerializationProperties() != null) { | |
| properties.getSerializationProperties().setProperties(serializationPropertiesMap); | |
| } | |
| if (properties.getDeserializationProperties() != null) { | |
| properties.getDeserializationProperties().setProperties(deserializationPropertiesMap); | |
| } | |
| return plugin.getSerializer(properties); | |
| } else { | |
| return null; | |
| } | |
| } | |
| } | |
| function getDefaultSerializationProperties(dataType) { | |
| var plugin = dataPlugins.get(dataType); | |
| if (plugin != null && plugin.getDefaultProperties().getSerializationProperties() != null) { | |
| return plugin.getDefaultProperties().getSerializationProperties().getProperties(); | |
| } else { | |
| return null; | |
| } | |
| } | |
| function getDefaultDeserializationProperties(dataType) { | |
| var plugin = dataPlugins.get(dataType); | |
| if (plugin != null && plugin.getDefaultProperties().getDeserializationProperties() != null) { | |
| return plugin.getDefaultProperties().getDeserializationProperties().getProperties(); | |
| } else { | |
| return null; | |
| } | |
| } | |
| return { | |
| getDefaultSerializationProperties: getDefaultSerializationProperties, | |
| getDefaultDeserializationProperties: getDefaultDeserializationProperties, | |
| getSerializer: getSerializer, | |
| addDataTypeServerPlugin: addDataTypeServerPlugin | |
| }; | |
| })(); | |
| function validate(mapping, defaultValue, replacement) { | |
| var result = (mapping == undefined) ? undefined : mapping; | |
| if ((result == undefined) || (result.toString().length == 0)) { | |
| if (defaultValue == undefined) { | |
| defaultValue = ''; | |
| } | |
| result = defaultValue; | |
| } | |
| if ('string' === typeof result || result instanceof java.lang.String || 'xml' === typeof result) { | |
| result = new java.lang.String(result.toString()); | |
| if (replacement != undefined) { | |
| for (var i = 0; i < replacement.length; i++) { | |
| var entry = replacement[i]; | |
| result = result.replaceAll(entry[0], entry[1]); | |
| } | |
| } | |
| } | |
| return result; | |
| }; | |
| // Helper function to create segments | |
| function createSegment(name, msgObj, index) { | |
| if (arguments.length == 1) { return new XML('<' + name + '></' + name + '>'); }; | |
| if (arguments.length == 2) { index = 0; }; | |
| msgObj[name][index] = new XML('<' + name + '></' + name + '>'); | |
| return msgObj[name][index]; | |
| }; | |
| // Helper function to create segments after specified field | |
| function createSegmentAfter(name, segment) { | |
| var msgObj = segment; | |
| while (msgObj.parent() != undefined) { msgObj = msgObj.parent(); } | |
| msgObj.insertChildAfter(segment[0], new XML('<' + name + '></' + name + '>')); | |
| return msgObj.child(segment[0].childIndex() + 1); | |
| }; | |
| // Helper function to get the length of an XMLList or array | |
| function getArrayOrXmlLength(obj) { | |
| if (typeof obj == 'xml' || obj instanceof java.lang.String) { | |
| return obj.length(); | |
| } else if (typeof obj != 'undefined' && obj != null) { | |
| return obj.length || 0; | |
| } | |
| return 0; | |
| }; | |
| // function $(variableName){ | |
| // if(variableName == 'isDebug') { | |
| // return false | |
| // } | |
| // if(variableName == 'countIndex') { | |
| // return null | |
| // } | |
| // } | |
| var mapObj = { | |
| "put": function(key,value){ | |
| this.storedValues[key] = value | |
| }, | |
| "storedValues":{}, | |
| "get": function(key){ | |
| return this.storedValues[key]; | |
| }, | |
| "containsKey": function(key){ | |
| if(typeof this.storedValues[key] != "undefined"){ | |
| return true; | |
| } | |
| return false; | |
| } | |
| } | |
| var connectorMap = mapObj | |
| var channelMap = mapObj | |
| var sourceMap = mapObj | |
| var globalChannelMap = mapObj | |
| var globalMap = mapObj | |
| var configurationMap = mapObj | |
| var responseMap = mapObj | |
| function $co(key, value) { if (arguments.length == 1) { return connectorMap.get(key); } else { return connectorMap.put(key, value); } } | |
| function $c(key, value) { if (arguments.length == 1) { return channelMap.get(key); } else { return channelMap.put(key, value); } } | |
| function $s(key, value) { if (arguments.length == 1) { return sourceMap.get(key); } else { return sourceMap.put(key, value); } } | |
| function $gc(key, value) { if (arguments.length == 1) { return globalChannelMap.get(key); } else { return globalChannelMap.put(key, value); } } | |
| function $g(key, value) { if (arguments.length == 1) { return globalMap.get(key); } else { return globalMap.put(key, value); } } | |
| function $cfg(key, value) { if (arguments.length == 1) { return configurationMap.get(key); } else { return configurationMap.put(key, value); } } | |
| function $r(key, value) { if (arguments.length == 1) { return responseMap.get(key); } else { return responseMap.put(key, value); } } | |
| function $(string) { | |
| try { if(responseMap.containsKey(string)) { return $r(string); } } catch(e){} | |
| try { if(connectorMap.containsKey(string)) { return $co(string); } } catch(e){} | |
| try { if(channelMap.containsKey(string)) { return $c(string); } } catch(e){} | |
| try { if(sourceMap.containsKey(string)) { return $s(string); } } catch(e){} | |
| try { if(globalChannelMap.containsKey(string)) { return $gc(string); } } catch(e){} | |
| try { if(globalMap.containsKey(string)) { return $g(string); } } catch(e){} | |
| try { if(configurationMap.containsKey(string)) { return $cfg(string); } } catch(e){} | |
| try { if(resultMap.containsKey(string)) { return resultMap.get(string); } } catch(e){} | |
| return ''; | |
| } | |
| var destinationSet = { | |
| "destinations": new java.util.HashMap(), | |
| "remove": function(destinationsToRemove) { | |
| if(Object.prototype.toString.call(destinationsToRemove) != '[object Array]'){ | |
| logger.error("destinations to be removed must be in an array") | |
| return false; | |
| } | |
| for(var i = 0; i < destinationsToRemove.length; i++){ | |
| this.destinations = this.destinations.splice(this.destinations.indexOf(destinationsToRemove[i]), 1); | |
| } | |
| return true; | |
| }, | |
| "removeAllExcept": function(destinationsToPreserve) { | |
| if(Object.prototype.toString.call(destinationsToPreserve) != '[object Array]'){ | |
| logger.error("destinations to be preserved must be in an array") | |
| return false; | |
| } | |
| // map removal adapted from https://stackoverflow.com/a/1884916 | |
| for(var i = this.destinations.entrySet().iterator(); i.hasNext(); ) { | |
| var entry = i.next(); | |
| if(!destinationsToPreserve.includes(String(entry.getKey()))) { | |
| i.remove(); | |
| } | |
| } | |
| return true; | |
| }, | |
| "removeAll": function() { | |
| this.destinations = []; | |
| return true; | |
| } | |
| } | |
| // the next two lines are for getting the current date and time in the local | |
| // timezone in ISO-8601 format without the 'T' separator | |
| // | |
| // Take from https://stackoverflow.com/a/28149561 | |
| var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds | |
| var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1).replace("T", " "); | |
| var logger = { | |
| "debug":function(message){ | |
| print("\033[30m" + localISOTime + "\t\033[34m[debug]\t\033[0m"+message) | |
| }, | |
| "error":function(message){ | |
| print("\033[30m" + localISOTime + "\t\033[31m[error]\t\033[0m"+message) | |
| }, | |
| "info":function(message){ | |
| print("\033[30m" + localISOTime + "\t\033[32m[info]\t\033[0m"+message) | |
| }, | |
| "warn":function(message){ | |
| print("\033[30m" + localISOTime + "\t\033[33m[warn]\t\033[0m"+message) | |
| } | |
| } | |
| var connectorMessage = { | |
| getMessageId: function(){ | |
| return 1234; | |
| }, | |
| getDestinationIdMap: function(){ | |
| return destinationSet.destinations; | |
| } | |
| } | |
| var serverName = java.net.InetAddress.getLocalHost().getHostName(); | |
| /************************************** | |
| * Run the file provided | |
| * | |
| * This was worked out with ChatGPT by Mike Hokanson | |
| * to allow for easier setup/testing via a build task | |
| * in VS Code | |
| **************************************/ | |
| if (arguments.length === 0) { | |
| print("❌ No script file passed to main.js"); | |
| quit(1); | |
| } | |
| load(arguments[0]); |
Author
@gibson9583 which OS are you using? I'm using Win11 with Mirth Connect 4.5.0 and using this task without issue.
Author
@gibson9583 - I don't know if this is still of interest to you, but I just updated the gist to not require loading the mirth stuff written by agermano in each script, but instead load as part of the build task.
Hey @mhokanson - yeah a little while back I had mine updated in a similar fashion.
Also, for reference to the previous comments (sorry for not replying) - I have been running this on MacOS. So my task is a little bit different for it to work properly.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Class path loads need to be updated for newer versions of mirth connect. When running 4.3.0, I had to explicitly load mirth-server.jar first, and needed to add hapi's path because of the server-lib directory structure change.