UNPKG

@atomic-ehr/fhirpath

Version:

A TypeScript implementation of FHIRPath

98 lines (84 loc) 3.67 kB
import type { FunctionDefinition, FunctionEvaluator, TypeInfo } from '../types'; import { Errors } from '../errors'; import { box, unbox } from '../boxing'; export const evaluate: FunctionEvaluator = async (input, context, args, evaluator) => { if (args.length !== 0) { throw Errors.wrongArgumentCount('children', 0, args.length); } const results: any[] = []; const modelProvider = context.modelProvider; // Process each item in the input collection // input is already an array, not an object with value property for (const boxedItem of input) { const item = unbox(boxedItem); if (item && typeof item === 'object') { // Get the parent type info if available let parentTypeInfo: TypeInfo | undefined; if (modelProvider && boxedItem.typeInfo) { parentTypeInfo = boxedItem.typeInfo; } else if (modelProvider && 'resourceType' in item && typeof item.resourceType === 'string') { // Try to get type info from resourceType (use cached version) parentTypeInfo = 'getTypeFromCache' in modelProvider ? (modelProvider as any).getTypeFromCache(item.resourceType) : undefined; } // Collect all child properties for (const propertyName in item) { // Skip resourceType as it's not a child element in FHIRPath if (propertyName === 'resourceType') { continue; } // Skip primitive element properties (those starting with _) if (propertyName.startsWith('_')) { continue; } const value = item[propertyName]; // Skip null/undefined values if (value === null || value === undefined) { continue; } // Get type info for this element from model provider let elementTypeInfo: TypeInfo | undefined; if (modelProvider && parentTypeInfo) { elementTypeInfo = await modelProvider.getElementType(parentTypeInfo, propertyName); } // Get primitive element if it exists const primitiveElementName = `_${propertyName}`; const primitiveElement = (primitiveElementName in item) ? item[primitiveElementName] : undefined; if (Array.isArray(value)) { // Add each array element for (let i = 0; i < value.length; i++) { const elementValue = value[i]; if (elementValue !== null && elementValue !== undefined) { const elementPrimitive = primitiveElement?.[i]; // Make the type info singleton since it's a single element const singletonTypeInfo = elementTypeInfo ? { ...elementTypeInfo, singleton: true } : undefined; results.push(box(elementValue, singletonTypeInfo, elementPrimitive)); } } } else { // Add single value - ensure it's marked as singleton const singletonTypeInfo = elementTypeInfo ? { ...elementTypeInfo, singleton: true } : undefined; results.push(box(value, singletonTypeInfo, primitiveElement)); } } } } return { value: results, context }; }; export const childrenFunction: FunctionDefinition & { evaluate: FunctionEvaluator } = { name: 'children', category: ['navigation'], description: 'Returns all immediate child nodes of all items in the input collection', examples: [ 'Patient.children()', 'Observation.children().ofType(CodeableConcept)' ], signatures: [{ name: 'children', input: { type: 'Any', singleton: false }, parameters: [], result: { type: 'Any', singleton: false } }], evaluate };