@atomic-ehr/fhirpath
Version:
A TypeScript implementation of FHIRPath
64 lines (56 loc) • 1.88 kB
text/typescript
import type { FunctionEvaluator } from '../types';
import { Errors } from '../errors';
import { childrenFunction } from './children-function';
/**
* descendants() - Returns all descendant nodes of items in the input collection
*
* Per FHIRPath spec:
* - Returns all descendants at any depth
* - Does NOT include the input nodes themselves
* - Equivalent to repeat(children())
* - Ordering is undefined
*
* Type analysis returns Any due to combinatorial explosion of possible types.
* In practice, users filter with ofType() or where() to get specific types.
*/
export const evaluate: FunctionEvaluator = async (input, context, args, evaluator) => {
if (args.length !== 0) {
throw Errors.wrongArgumentCount('descendants', 0, args.length);
}
const results: any[] = [];
const queue: any[] = [...input];
// Breadth-first traversal using queue
while (queue.length > 0) {
const current = queue.shift()!;
// Get children through existing children() function
const childrenResult = await childrenFunction.evaluate(
[current],
context,
[],
evaluator
);
// Add all children to results and queue for further processing
for (const boxedChild of childrenResult.value) {
results.push(boxedChild);
queue.push(boxedChild);
}
}
return { value: results, context };
};
export const descendantsFunction = {
name: 'descendants',
category: ['navigation'],
description: 'Returns all descendant nodes at any depth (not including input nodes)',
examples: [
'Bundle.descendants().ofType(Reference)',
'Patient.descendants().ofType(CodeableConcept)',
'Questionnaire.descendants().linkId'
],
signatures: [{
name: 'descendants',
input: { type: 'Any', singleton: false },
parameters: [],
result: { type: 'Any', singleton: false }
}],
evaluate
};