Skip to content

Commit

Permalink
Merge pull request #7 from papaemmelab/add-typescript
Browse files Browse the repository at this point in the history
🛠  Add typescript
  • Loading branch information
juanesarango authored Dec 12, 2023
2 parents 654743a + 8fd34e8 commit 9b52b13
Show file tree
Hide file tree
Showing 19 changed files with 556 additions and 271 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/cli-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Can be run as CLI

on: [push]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: '18.x'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Install CLI globally
run: npm install -g .

- name: Test CLI
run: |
# Run the CLI with the example file
OUTPUT=$(ipssm test/data/IPSSMexample.csv test.csv)
echo "$OUTPUT"
# Check the stout for the expected output
if ! echo "$OUTPUT" | grep -q "File annotated successfully."; then
echo "CLI execution didn't work"
exit 1
fi
8 changes: 2 additions & 6 deletions .github/workflows/risk-scores-test.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
name: Compute IPSS-M and IPSS-M Risks on IWG-PM Cohort (Bernard et al, 2022 NJEM Evid)

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
on: [push]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [ 14.x ]
node-version: [ 18.x ]

steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Node modules
node_modules
test/data/*-out.*

# Compiled JS files
dist

# Data test files
test/data/*-out.*
test.csv
72 changes: 68 additions & 4 deletions package-lock.json

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

12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
"version": "1.0.4",
"description": "Javascript Package for the Molecular International Prognostic Scoring System (IPSS-M) for Myelodysplastic Syndromes.",
"main": "index.js",
"type": "module",
"type": "commonjs",
"bin": {
"ipssm": "./bin/cli.js"
"ipssm": "./dist/cli.js"
},
"directories": {
"test": "test"
},
"scripts": {
"test": "vitest"
"test": "vitest",
"build": "tsc"
},
"repository": {
"type": "git",
Expand All @@ -30,10 +31,15 @@
},
"homepage": "https://github.com/papaemmelab/ipssm-js#readme",
"devDependencies": {
"@types/node": "^20.10.4",
"@types/papaparse": "^5.3.14",
"@types/yargs": "^17.0.32",
"typescript": "^5.3.3",
"vitest": "^0.34.4"
},
"dependencies": {
"exceljs": "^4.3.0",
"ipssm": "^1.0.4",
"papaparse": "^5.4.1",
"yargs": "^17.7.2"
}
Expand Down
9 changes: 5 additions & 4 deletions bin/cli.js → src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'
import { annotateFile } from '../index.js'
import { annotateFile } from './index'

const argv = yargs(hideBin(process.argv))
.usage('Annotate file with IPSS-M and IPSS-R.\n\nUsage: $0 <inputFile> <outputFile>')
.command(
'$0 <inputFile> <outputFile>',
'',
'Annotate with IPSS-M and IPSS-R a file with patients.',
(yargs) => {
yargs
.positional('inputFile', {
Expand All @@ -27,13 +27,14 @@ const argv = yargs(hideBin(process.argv))
.example('$0 in.csv out.csv', 'annotate a csv file.')
.help('h')
.alias('h', 'help')
.argv
.argv;

(async () => {
try {
// @ts-ignore
await annotateFile(argv.inputFile, argv.outputFile)
console.log('File annotated successfully.')
} catch (error) {
console.error('Error annotating file:', error.message)
console.error('Error annotating file:', (error as Error).message)
}
})()
44 changes: 24 additions & 20 deletions index.js → src/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { processInputs } from './utils/preprocess.js'
import { computeIpssm, computeIpssr as ipssr } from './utils/risk.js'
import { parseCsv, parseXlsx, writeCsv, writeXlsx } from './utils/parseFile.js'
import { PatientInput, PatientOutput, IpssmScores, PatientForIpssr, CsvData } from './types'
import { processInputs } from './utils/preprocess'
import { computeIpssm, computeIpssr as ipssr } from './utils/risk'
import { parseCsv, parseXlsx, writeCsv, writeXlsx } from './utils/parseFile'

// IPSS-M risk score method
const ipssm = (patientInput) => {
const ipssm = (patientInput: PatientInput): IpssmScores => {
const processed = processInputs(patientInput)
return computeIpssm(processed)
}

// IPSS-M, IPSS-R, and IPSS-RA risks score from a csv/xlsx file method
const annotateFile = async (inputFile, outputFile, skipIpssr=false) => {
const annotateFile = async (inputFile: string, outputFile: string, skipIpssr: boolean = false): Promise<void> => {

if (!inputFile || !outputFile) {
throw new Error('Input and output files are required')
}

let patients = []
let patients: PatientInput[] = []
if (inputFile.endsWith('.csv') || inputFile.endsWith('.tsv')) {
patients = await parseCsv(inputFile)
} else if (inputFile.endsWith('.xlsx')) {
Expand All @@ -24,10 +25,11 @@ const annotateFile = async (inputFile, outputFile, skipIpssr=false) => {
throw new Error('File type not supported')
}

const annotatedPatients = patients.map((patient) => {
const annotatedPatients: PatientOutput[] = patients.map((patient) => {
// Calculate IPSS-M and add to patient object
const ipssmResult = ipssm(patient)
// Add IPSS-M results to patient object
patient = {

let annotatedPatient: PatientOutput = {
...patient,
IPSSM_SCORE: ipssmResult.means.riskScore,
IPSSM_CAT: ipssmResult.means.riskCat,
Expand All @@ -37,27 +39,29 @@ const annotateFile = async (inputFile, outputFile, skipIpssr=false) => {
IPSSM_CAT_WORST: ipssmResult.worst.riskCat,
}

if (!skipIpssr) {
const ipssrResult = ipssr({
if (!skipIpssr && patient.ANC !== undefined && patient.ANC !== null) {
// Calculate IPSS-R and add to patient object
const data: PatientForIpssr = {
bmblast: patient.BM_BLAST,
hb: patient.HB,
anc: patient.ANC,
plt: patient.PLT,
bmblast: patient.BM_BLAST,
anc: patient.ANC,
cytoIpssr: patient.CYTO_IPSSR,
age: patient.AGE,
})
}

const ipssrResult = ipssr(data)

// Add IPSS-R results to patient object
patient = {
...patient,
annotatedPatient = {
...annotatedPatient,
IPSSR_SCORE: ipssrResult.IPSSR_SCORE,
IPSSR_CAT: ipssrResult.IPSSR,
IPSSR_CAT: ipssrResult.IPSSR_CAT,
IPSSRA_SCORE: ipssrResult.IPSSRA_SCORE,
IPSSRA_CAT: ipssrResult.IPSSRA,
IPSSRA_CAT: ipssrResult.IPSSRA_CAT,
}
}

return patient
return annotatedPatient
})

// Create new csv file with annotated patients
Expand Down
Loading

0 comments on commit 9b52b13

Please sign in to comment.