@atomic-ehr/fhirpath
Version:
A TypeScript implementation of FHIRPath
82 lines (66 loc) • 2.58 kB
text/typescript
import type { FunctionDefinition, FunctionEvaluator } from '../types';
import { Errors } from '../errors';
import { box, unbox } from '../boxing';
export const evaluate: FunctionEvaluator = async (input, context, args, evaluator) => {
// Handle empty input collection
if (input.length === 0) {
return { value: [], context };
}
// If input contains multiple items, signal an error
if (input.length > 1) {
throw Errors.invalidOperation('toDecimal can only be applied to a singleton');
}
// toDecimal() takes no arguments
if (args && args.length > 0) {
throw Errors.invalidOperation('toDecimal does not take any arguments');
}
const boxedInputValue = input[0];
if (!boxedInputValue) {
return { value: [], context };
}
const inputValue = unbox(boxedInputValue);
// Handle different input types according to spec
// Integer or Decimal - return as decimal
if (typeof inputValue === 'number') {
return { value: [box(inputValue, { type: 'Decimal', singleton: true })], context };
}
// Boolean - true -> 1.0, false -> 0.0
if (typeof inputValue === 'boolean') {
return { value: [box(inputValue ? 1.0 : 0.0, { type: 'Decimal', singleton: true })], context };
}
// String - try to convert to decimal
if (typeof inputValue === 'string') {
// Use the regex from the spec: (\+|-)?\d+(\.\d+)?
const decimalRegex = /^(\+|-)?\d+(\.\d+)?$/;
if (!decimalRegex.test(inputValue)) {
// String is not convertible to decimal
return { value: [], context };
}
const parsedValue = parseFloat(inputValue);
// Check for valid number
if (isNaN(parsedValue)) {
return { value: [], context };
}
return { value: [box(parsedValue, { type: 'Decimal', singleton: true })], context };
}
// For any other type, return empty
return { value: [], context };
};
export const toDecimalFunction: FunctionDefinition & { evaluate: FunctionEvaluator } = {
name: 'toDecimal',
category: ['type-conversion'],
description: 'Converts the input to a Decimal value. Returns a single decimal for Integer, Decimal, convertible String, or Boolean inputs. Returns empty for non-convertible values.',
examples: [
"'3.14'.toDecimal() // returns 3.14",
"42.toDecimal() // returns 42.0",
"true.toDecimal() // returns 1.0",
"false.toDecimal() // returns 0.0"
],
signatures: [{
name: 'toDecimal',
input: { type: 'Any', singleton: true },
parameters: [],
result: { type: 'Decimal', singleton: true }
}],
evaluate
};