qiprofile
Version:
Quantitative Imaging Profile ( QiPr) web application
106 lines (94 loc) • 3.71 kB
text/coffeescript
define ['angular', 'lodash', 'breast', 'sarcoma'], (ng, _) ->
tnm = ng.module 'qiprofile.tnm', ['qiprofile.breast', 'qiprofile.sarcoma']
tnm.factory 'TNM', ['Breast', 'Sarcoma', (Breast, Sarcoma) ->
# The supported tumor type-specific services.
TUMOR_TYPE_SERVICES =
Breast: Breast
Sarcoma: Sarcoma
# @param tumorType the tumor type name, e.g. 'Breast'
# @returns the tumorTypeService factory for that tumor type
tumorTypeService = (tumorType) ->
TUMOR_TYPE_SERVICES[tumorType] or
throw new ReferenceError("Unsupported tumor type: #{ tumorType }")
# Define here for reuse below.
_summaryGrade = (tnm) ->
# Calculates the cumulative grade as the sum of the component
# tumor type factory SCORES property values.
#
# @param tnm the TNM object
# @returns the cumulative grade, or null if a score is missing
cumulativeGrade = ->
accumulate = (sum, prop) ->
sum + grade[prop]
return null unless grade?
props = tumorTypeService(tnm.tumorType).Grade.SCORES
if _.every(props, (prop) -> grade[prop]?)
_.reduce(props, accumulate, 0)
else
null
grade = tnm.grade
if not grade?
return null
# The sum of the relevant grade properties.
cGrade = cumulativeGrade()
if not cGrade? then return null
# The tumor type grade ranges.
ranges = tumorTypeService(tnm.tumorType).Grade.RANGES
inRange = (range) -> cGrade in range
index = _.findIndex(ranges, inRange)
if index < 0
throw new ReferenceError("Unsupported #{ tnm.tumorType }" +
" cumulative grade: #{ cGrade }")
# Return the one-based summary grade value.
1 + index
# @param size the size composite object
# @returns the standard size string, e.g. 'p2b'
# @throws Error if the tumorSize property value is missing
formatSize: (size) ->
sizeSuffix = ->
inSituSuffix = (inSitu) ->
if size.inSitu.invasiveType is 'ductal'
'is(DCIS)'
else if size.inSitu.invasiveType is 'lobular'
'is(LCIS)'
else
'is'
# The size suffix can be a, b, c or is.
# in situ (is) can be modified with the invasive
# type (ductal or lobular).
if size.inSitu?
inSituSuffix(size.inSitu)
else if size.suffix?
size.suffix
else
''
if not size.tumorSize?
throw new Error("The TNM tumor size is missing")
prefix = size.prefix or ''
suffix = sizeSuffix()
"#{ prefix }#{ size.tumorSize }#{ suffix }"
# Calculates the summary grade based on the cumulative grade
# as defined in the tumor type factory RANGES lookup table.
#
# @param grade the grade composite object
# @returns the summary grade
# @throws ReferenceError if the grade scores are not supported
summaryGrade: _summaryGrade
# Calculates the tumor stage for the given TNM composite
# object.
#
# This function returns the cancer stage as a string
# consisting of a digit in the range 1 to 4 optionally
# followed by a suffix A, B or C. This facilitates
# accurate comparison, in contrast to the roman numeral
# grade, e.g. '1A' < '2B' , but 'IA' > 'IIB'.
# The romanize filter can be used to display the stage
# in the standard archaic medical format.
#
# @param tnm the TNM object.
# @returns the cancer stage object
stage: (tnm) ->
grade = _summaryGrade(tnm)
# Delegate to the tumor type service.
tumorTypeService(tnm.tumorType).stage(tnm, grade)
]