Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

ClinSpark supports “Formal Expressions” through Javascript. This is the Javascript code which gets executed to accomplish the task. It is the contents of a method, which makes some calculation, performs whatever logic is required to implement either the MethodDef or the RangeCheck.

Here’s an example of a method in ClinSpark which calculates BMI. It is designed to be associated with a Item who has other Items named Height and Weight. It retrieves these values from JSON passed to the method, performs the calculation, then returns a JSON response which includes the units.

...

Note that the Context value in the ClinSpark implementation is used for reference only, it does not impact the execution of the expression in any way.

The return requirements for a Method are a value if the function does not need units, or a JSON object as shown above if units must be specified.

Formal Expression Dev Tooling in ClinSpark

Note that this tooling was introduced in ClinSpark 1.5.2.

To support self-serve formal expression development and testing by customers, an embedded editor and test execution harness has been added to ClinSpark. Here is where it can be accessed:

...

This tooling applies to BOTH Methods and Edit Checks. You will see that the same test harness is present in the editing UI for both of these features.

Here is an overview of the editor and testing harness:

...

Red dot

...

Description

...

1

...

This is an embedded Javascript editor. It supports appropriate highlighting and basic syntax checking. Note the warnings and errors in the left sidebar.

...

2

...

Info

ClinSpark currently uses the Mozilla Rhino Javascript engine bundled with Java 7. This implementation of Rhino is based on version 1.7R3 pre-release sources with Oracle modifications.
https://www.oracle.com/java/technologies/javase/7u1-relnotes.html

The ClinSpark product team is evaluating support for more modern Javascript engines in a future release. Customers that have feedback on this topic are encouraged to reach out via service desk with questions or concerns.

Here’s an example of a method in ClinSpark which calculates BMI. It is designed to be associated with a Item who has other Items named Height and Weight. It retrieves these values from JSON passed to the method, performs the calculation, then returns a JSON response which includes the units.

...

Note that the Context value in the ClinSpark implementation is used for reference only, it does not impact the execution of the expression in any way.

The return requirements for a Method are a value if the function does not need units, or a JSON object as shown above if units must be specified.

Formal Expression Dev Tooling in ClinSpark

To support self-serve formal expression development and testing by customers, an embedded editor and test execution harness exists within ClinSpark. Here is where it can be accessed:

...

Info

This tooling applies to both Methods and Edit Checks. You will see that the same test harness is present in the editing UI for both of these features.

Here is an overview of the editor and testing harness:

...

Red dot

Description

1

This is an embedded Javascript editor. It supports appropriate highlighting and basic syntax checking. Note the warnings and errors in the left sidebar.

2

Guidance on using the logger function to gain insight into the inner workings of your code. This is crucial during development and troubleshooting.

3

To execute the expression against collected itemData, this field accepts the database ID of an itemData. Details to follow on how to obtain this value.

4

Executes the method from #1 against the itemData specified in #3 and displays the output along with any logger content. This allows testing and troubleshooting against actual data, without requiring additional collection activities.

5

Displays the available ClinSpark-provided Javascript functions which will be available to the expression at runtime.

6

Downloads the JSON contents of the itemData from #3 as a file. This may be useful, but note that you can also use logger(JSON.stringify(itemJson, null, 2)); and also logger(JSON.stringify(formJson, null, 2)); to see this output dynamically as well.

...

From there you can format it using the tool of your choice to see the output you’re looking for. A Google search for “prettify JSON” will help locate free online tools; the Foundry Health internal team uses VS Code to do this.

Code Block
{
    "item": {
        "nameid": "VS_Significance"136424,         "dataType": "string",           "dataCollectionStatus": "Unsaved", // Unique ID for the item data
 "sasFieldName": "VSCLSIG",
        "codeListItemsname": ["AE_START_DATE",           // Name {of the item (e.g., 'Adverse Event Start  Date')
        "codedValuedataType": "CSincompleteDatetime",  // Data type (e.g., 'string', 'date', 'incompleteDatetime')
        "decodedataCollectionStatus": "Clinically Significant"
    Complete",// Status: 'Complete', 'In Progress', etc.
       },
   "sasFieldName": "AESTDTC",         // {Corresponding SAS field      name
        "codedValuevalue": "NCS2024-08- T13:39: ",      // Captured value (can be incomplete)
        "decodecodeListItems": "Not[ Clinically Significant"             }  // Optional: List of allowed coded values
],         "measurementUnits": [],  {
      "measurementUnit": null,         "valuecodedValue": null"CS",         "outOfRange": false,
// Coded value
       "nonconformantMessage": null,        "decode": "lengthClinically Significant": null,// Meaning of coded value
    "significantDigits": null,        },
            {
     "canceled           "codedValue": false"NCS",
             }
}

formJson

The formJson object contains the complete formData along with all contained itemGroupData and their child itemData.

In addition, quite a bit of context metadata can be found within the formJson object:

Code Block
"form": {
   "decode": "Not Clinically Significant"
   "name": "Demographics",     "studyEventName": "Day -28 to}
Day -2",     "cohort": {
        "id": 88 ],
        "namemeasurementUnits": "12Nov2020"[],         "epoch": {
  // Array of applicable measurement units
         "idmeasurementUnit": 80null,       // Specific measurement unit (if used)
        "nameoutOfRange": "Screening" true,            }// Whether the value  },
 is out of an acceptable range
  "timepoint": null,     "cancelednonconformantMessage": falsenull,  // Message if the "dataCollectionStatus": "Complete"

Here you will also find metadata about the subject/volunteer

Code Block
"subject": {item is nonconformant
    "id": 165,     "lockedlength": falsenull,     "screeningNumber": "S440113001",     "leadInNumber": "L0001",    // "randomizationNumber"Optional: "1302",Length constraint for the  "subjectStudyStatus": "Active",value
        "subjectEligibilityTypesignificantDigits": "Unspecified"null,     // "volunteer": {Optional: Number of significant digits allowed
        "idcanceled": 135,false         "initials": "M-M",    // Whether this item has "age": 30,been canceled
    }
}

formJson

The formJson object contains the complete formData along with all contained itemGroupData and their child itemData.

In addition, quite a bit of context metadata can be found within the formJson object:

Code Block
{
    "sexMaleform": true,{
        "dateOfBirthname": "1990-XX-05"Form Name",             }
}

All of this data can be directly accessed from the expression.

findFormData - looking up previous formData

Sometimes you will need to lookup up other collected data for a subject. For instance this might allow a comparison of a value to a baseline, or retrieve other data imported from a volunteer record demographic form.

To see an example of using this method, search for the Triplicate Reading Average example in the Method library. This method retrieves 3 previously collected ECG readings and then produces an average.

findFormData supports querying for previously collected formData of this same subject only.

Guidelines and Suggestions

...

   // Name of the form (e.g., 'Demographics')
        "studyEventName": "Event Name",      // Name of the study event
        "cohort": {                         // Cohort-related metadata
            "id": 88,
            "name": "Cohort Name",
            "epoch": {
                "id": 80,
                "name": "Screening"         // Epoch or phase name
            }
        },
        "timepoint": null,                   // Timepoint (if applicable)
        "canceled": false,                   // Whether the form is canceled
        "dataCollectionStatus": "Complete",  // Status: Complete, In Progress, etc.
        "subject": {                         // Information about the subject/volunteer
            "id": 165,
            "screeningNumber": "S440113001", // Subject screening number
            "randomizationNumber": "1302",   // Randomization number
            "subjectStudyStatus": "Active",  // Status of subject in study
            "volunteer": {                   // Volunteer details
                "id": 135,
                "initials": "M-M",
                "age": 30,
                "sexMale": true,
                "dateOfBirth": "1990-XX-05" // Supports incomplete dates
            }
        },
        "itemGroups": [                     // Array of item groups within the form
            {
                "itemGroupRepeatKey": 1,    // Identifier for repeated groups
                "items": [                  // Array of individual items
                    {
                        "name": "Item Name",   // Name of the item
                        "dataType": "string",  // Data type (e.g., string, date, etc.)
                        "value": "some value", // Collected data value
                        "canceled": false,     // Whether the item is canceled
                        "sasFieldName": "SAS_NAME", // SAS field name mapping
                        "codeListItems": []    // Optional: Code list if applicable
                    }
                ]
            }
        ]
    }
}

All of this data can be directly accessed from the expression.

findFormData - looking up previous formData

Sometimes you will need to lookup up other collected data for a subject. For instance this might allow a comparison of a value to a baseline, or retrieve other data imported from a volunteer record demographic form.

To see an example of using this method, search for the Triplicate Reading Average example in the Method library. This method retrieves 3 previously collected ECG readings and then produces an average.

findFormData supports querying for previously collected formData of this same subject only.

Guidelines and Suggestions

Define variables up top to support reusability across studies. See the examples in the Method Library section of this help site.

Errors/warnings in the Formal Expressions syntax checker

The syntax checker by default validates code as “strict mode” JavaScript. If the JavaScript code is not marked 'use strict'  at the start of the file, you may get an error saying:
"Too many errors. (nn% Scanned)"

...

There are two ways to fix this.

1, Tell the syntax checker you are not using strict mode, paste this at the first line:
/* jshint strict: false */

2, If you want to write JavaScript in strict mode, and get strict mode syntax checking, paste this in the first two lines:
/* globals itemJson, formJson, findFormData, logger, customErrorMessage, findCompletedFormData, findFormData, getItemDataContext */
'use strict';

If you are using other implicit data/methods not included here and get “undefined variable” errors in those lines, add those variables/functions to the list of “globals”.

The list is needed because the editor would flag our implicit methods and implicit data as undefined variables.