@atomic-ehr/fhirpath 0.0.5 → 0.1.0-canary.20260203155750.e52d2f6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- import { F as FHIRModelProviderBase, R as Resource } from './model-provider.common-oir-zg7r.js';
2
- export { q as ASTMetadata, i as ASTNode, h as AnalysisResult, A as Analyzer, N as AnyCursorNode, w as CompletionItem, C as CompletionKind, x as CompletionOptions, J as CursorArgumentNode, y as CursorContext, H as CursorIdentifierNode, K as CursorIndexNode, B as CursorNode, G as CursorOperatorNode, L as CursorTypeNode, f as Diagnostic, D as DiagnosticSeverity, u as ErrorCodes, t as Errors, E as EvaluateOptions, l as EvaluationResult, a as FHIRModelContext, s as FHIRPathError, k as FunctionDefinition, n as InspectOptions, o as InspectResult, I as Interpreter, M as ModelTypeProvider, O as OperatorDefinition, d as ParseResult, P as Parser, c as Registry, T as TypeInfo, j as TypeName, b as analyze, e as evaluate, g as getVersion, m as inspect, z as isCursorNode, p as parse, v as provideCompletions, r as registry } from './model-provider.common-oir-zg7r.js';
1
+ import { F as FHIRModelProviderBase, R as Resource } from './model-provider.common-BULsr92N.js';
2
+ export { q as ASTMetadata, i as ASTNode, h as AnalysisResult, A as Analyzer, N as AnyCursorNode, w as CompletionItem, C as CompletionKind, x as CompletionOptions, J as CursorArgumentNode, y as CursorContext, H as CursorIdentifierNode, K as CursorIndexNode, B as CursorNode, G as CursorOperatorNode, L as CursorTypeNode, f as Diagnostic, D as DiagnosticSeverity, u as ErrorCodes, t as Errors, E as EvaluateOptions, l as EvaluationResult, a as FHIRModelContext, s as FHIRPathError, k as FunctionDefinition, n as InspectOptions, o as InspectResult, I as Interpreter, M as ModelTypeProvider, O as OperatorDefinition, d as ParseResult, P as Parser, c as Registry, T as TypeInfo, j as TypeName, b as analyze, e as evaluate, g as getVersion, m as inspect, z as isCursorNode, p as parse, v as provideCompletions, r as registry } from './model-provider.common-BULsr92N.js';
3
3
  import '@atomic-ehr/fhirschema';
4
4
 
5
5
  interface FHIRModelProviderConfig {
@@ -14,7 +14,7 @@ declare class FHIRModelProvider extends FHIRModelProviderBase {
14
14
  private config;
15
15
  private canonicalManager;
16
16
  prepare(): Promise<void>;
17
- resolve(canonicalUrl: string): Promise<Resource>;
17
+ resolve(typeName: string): Promise<Resource>;
18
18
  search(params: {
19
19
  kind: 'primitive-type' | 'complex-type' | 'resource';
20
20
  }): Promise<Resource[]>;
@@ -2268,6 +2268,8 @@ __export(operations_exports, {
2268
2268
  extensionFunction: () => extensionFunction,
2269
2269
  firstFunction: () => firstFunction,
2270
2270
  floorFunction: () => floorFunction,
2271
+ getReferenceKeyFunction: () => getReferenceKeyFunction,
2272
+ getResourceKeyFunction: () => getResourceKeyFunction,
2271
2273
  greaterOperator: () => greaterOperator,
2272
2274
  greaterOrEqualOperator: () => greaterOrEqualOperator,
2273
2275
  hasValueFunction: () => hasValueFunction,
@@ -11582,6 +11584,133 @@ var expFunction = {
11582
11584
  evaluate: evaluate105
11583
11585
  };
11584
11586
 
11587
+ // src/operations/getResourceKey-function.ts
11588
+ var evaluate106 = async (input, context, args, evaluator) => {
11589
+ const results = [];
11590
+ for (const boxedItem of input) {
11591
+ const item = unbox(boxedItem);
11592
+ if (item && typeof item === "object") {
11593
+ if ("id" in item && item.id !== void 0) {
11594
+ results.push(box(String(item.id), { type: "String", singleton: true }));
11595
+ }
11596
+ }
11597
+ }
11598
+ return { value: results, context };
11599
+ };
11600
+ var getResourceKeyFunction = {
11601
+ name: "getResourceKey",
11602
+ category: ["SQL on FHIR", "navigation"],
11603
+ description: "Returns a unique key identifying this resource for use in database joins. The returned value can be used with getReferenceKey() to join resources. This is typically the resource id, but the exact format is implementation-dependent.",
11604
+ examples: [
11605
+ "getResourceKey()",
11606
+ "Patient.getResourceKey()"
11607
+ ],
11608
+ signatures: [{
11609
+ name: "getResourceKey",
11610
+ input: { type: "Any", singleton: false, name: "Resource" },
11611
+ parameters: [],
11612
+ result: { type: "String", singleton: false }
11613
+ }],
11614
+ evaluate: evaluate106
11615
+ };
11616
+
11617
+ // src/operations/getReferenceKey-function.ts
11618
+ init_errors();
11619
+ init_types();
11620
+ function parseReference(reference) {
11621
+ if (!reference) return null;
11622
+ if (reference.startsWith("urn:")) {
11623
+ return { id: reference };
11624
+ }
11625
+ if (reference.includes("://")) {
11626
+ const url = reference.split("?")[0];
11627
+ const segments = url.split("/").filter((s) => s);
11628
+ if (segments.length >= 2) {
11629
+ const id = segments[segments.length - 1];
11630
+ const resourceType = segments[segments.length - 2];
11631
+ return { resourceType, id };
11632
+ }
11633
+ return null;
11634
+ }
11635
+ const parts = reference.split("/");
11636
+ if (parts.length === 2) {
11637
+ return { resourceType: parts[0], id: parts[1] };
11638
+ }
11639
+ if (reference.startsWith("#")) {
11640
+ return { id: reference.substring(1) };
11641
+ }
11642
+ return null;
11643
+ }
11644
+ function extractTypeName(typeArg) {
11645
+ if (isIdentifierNode(typeArg)) {
11646
+ return typeArg.name;
11647
+ } else if (isFunctionNode(typeArg) && isIdentifierNode(typeArg.name)) {
11648
+ return typeArg.name.name;
11649
+ }
11650
+ throw Errors.invalidOperation(`getReferenceKey() requires a type name as argument, got ${typeArg.type}`);
11651
+ }
11652
+ var evaluate107 = async (input, context, args, evaluator) => {
11653
+ let targetResourceType;
11654
+ if (args.length > 0) {
11655
+ targetResourceType = extractTypeName(args[0]);
11656
+ }
11657
+ const results = [];
11658
+ for (const boxedItem of input) {
11659
+ const item = unbox(boxedItem);
11660
+ if (!item || typeof item !== "object") {
11661
+ continue;
11662
+ }
11663
+ let referenceString;
11664
+ if ("reference" in item && typeof item.reference === "string") {
11665
+ referenceString = item.reference;
11666
+ } else if (typeof item === "string") {
11667
+ referenceString = item;
11668
+ }
11669
+ if (!referenceString) {
11670
+ continue;
11671
+ }
11672
+ const parsed = parseReference(referenceString);
11673
+ if (!parsed || !parsed.id) {
11674
+ continue;
11675
+ }
11676
+ if (targetResourceType) {
11677
+ if (!parsed.resourceType || parsed.resourceType !== targetResourceType) {
11678
+ continue;
11679
+ }
11680
+ }
11681
+ results.push(box(parsed.id, { type: "String", singleton: true }));
11682
+ }
11683
+ return { value: results, context };
11684
+ };
11685
+ var getReferenceKeyFunction = {
11686
+ name: "getReferenceKey",
11687
+ category: ["SQL on FHIR", "navigation"],
11688
+ description: "Returns a foreign key from a Reference element for joining to another resource. The returned value equals getResourceKey() on the referenced resource. If resourceType is provided, returns empty if the reference is not of that type.",
11689
+ examples: [
11690
+ "subject.getReferenceKey()",
11691
+ "subject.getReferenceKey(Patient)",
11692
+ "Observation.subject.getReferenceKey(Patient)"
11693
+ ],
11694
+ signatures: [
11695
+ {
11696
+ name: "getReferenceKey",
11697
+ input: { type: "Any", singleton: false, name: "Reference" },
11698
+ parameters: [
11699
+ {
11700
+ name: "resourceType",
11701
+ type: { type: "Any", singleton: true },
11702
+ optional: true,
11703
+ expression: true,
11704
+ typeReference: true
11705
+ // Expects a type name like Patient, Observation
11706
+ }
11707
+ ],
11708
+ result: { type: "String", singleton: false }
11709
+ }
11710
+ ],
11711
+ evaluate: evaluate107
11712
+ };
11713
+
11585
11714
  // src/registry.ts
11586
11715
  var Registry = class {
11587
11716
  constructor() {
@@ -13065,11 +13194,11 @@ function specificity(actual, required) {
13065
13194
  if (numeric.has(actual.type) && numeric.has(required.type)) return 2;
13066
13195
  return 1;
13067
13196
  }
13068
- function matchFunctionSignature(input, args, def) {
13197
+ function matchFunctionSignature(input, args, def, resourceTypes) {
13069
13198
  if (!def || !def.signatures || def.signatures.length === 0) return void 0;
13070
13199
  let best;
13071
13200
  for (const sig of def.signatures) {
13072
- if (sig.input && !isFunctionTypeCompatible(input, sig.input)) {
13201
+ if (sig.input && !isFunctionTypeCompatible(input, sig.input, resourceTypes)) {
13073
13202
  continue;
13074
13203
  }
13075
13204
  let ok = true;
@@ -13106,8 +13235,16 @@ function matchFunctionSignature(input, args, def) {
13106
13235
  }
13107
13236
  return best?.sig;
13108
13237
  }
13109
- function isFunctionTypeCompatible(actual, expected) {
13238
+ function isFunctionTypeCompatible(actual, expected, resourceTypes) {
13110
13239
  if (expected.singleton && !actual.singleton) return false;
13240
+ if (expected.name && actual.name) {
13241
+ if (expected.name === "Resource") {
13242
+ if (actual.name === "Resource") return true;
13243
+ if (resourceTypes) return resourceTypes.has(actual.name);
13244
+ return true;
13245
+ }
13246
+ if (expected.name !== actual.name) return false;
13247
+ }
13111
13248
  if (expected.type === "Any") return true;
13112
13249
  if (actual.type === expected.type) return true;
13113
13250
  if (expected.type === "Decimal" && actual.type === "Integer") return true;
@@ -13214,6 +13351,7 @@ function checkParamTypes(sig, argTypes, nodes, opts) {
13214
13351
  init_errors();
13215
13352
  var Analyzer = class _Analyzer {
13216
13353
  constructor(modelProvider) {
13354
+ this.resourceTypesCache = null;
13217
13355
  this.cursorMode = false;
13218
13356
  this.stoppedAtCursor = false;
13219
13357
  this.modelProvider = modelProvider;
@@ -13559,7 +13697,12 @@ var Analyzer = class _Analyzer {
13559
13697
  const diagnostics = [];
13560
13698
  let match = null;
13561
13699
  if (!hasArityError && funcDef.signatures && funcDef.signatures.length > 0) {
13562
- match = matchFunctionSignature(actualInput, argTypes, funcDef) || null;
13700
+ match = matchFunctionSignature(
13701
+ actualInput,
13702
+ argTypes,
13703
+ funcDef,
13704
+ this.resourceTypesCache ?? void 0
13705
+ ) || null;
13563
13706
  if (!match) {
13564
13707
  const inputIsEmpty = isEmptyCollection(actualInput);
13565
13708
  if (inputIsEmpty && !funcDef.doesNotPropagateEmpty) {
@@ -13582,7 +13725,11 @@ var Analyzer = class _Analyzer {
13582
13725
  const expectedInput = sig.input;
13583
13726
  const singletonMatch = !expectedInput.singleton || actualInput.singleton === true;
13584
13727
  const typeMatch = expectedInput.type === "Any" || actualInput.type === "Any" || expectedInput.type === actualInput.type || expectedInput.type === "Decimal" && actualInput.type === "Integer";
13585
- inputMatches = singletonMatch && typeMatch;
13728
+ let nameMatch = !expectedInput.name || !actualInput.name || expectedInput.name === actualInput.name;
13729
+ if (expectedInput.name === "Resource" && actualInput.name) {
13730
+ nameMatch = actualInput.name === "Resource" || (this.resourceTypesCache?.has(actualInput.name) ?? true);
13731
+ }
13732
+ inputMatches = singletonMatch && typeMatch && nameMatch;
13586
13733
  }
13587
13734
  if (inputMatches) {
13588
13735
  inputMatchingSignature = sig;
@@ -13598,7 +13745,8 @@ var Analyzer = class _Analyzer {
13598
13745
  })
13599
13746
  );
13600
13747
  } else {
13601
- const actualTypeStr = actualInput.singleton ? actualInput.type : `${actualInput.type}[]`;
13748
+ const actualTypeName = actualInput.name || actualInput.type;
13749
+ const actualTypeStr = actualInput.singleton ? actualTypeName : `${actualTypeName}[]`;
13602
13750
  const hasSingletonSignature = funcDef.signatures.some((sig) => sig.input?.singleton && sig.input.type === actualInput.type);
13603
13751
  const permissive = ["anyFalse", "anyTrue"];
13604
13752
  if (hasSingletonSignature && !actualInput.singleton) {
@@ -13610,7 +13758,11 @@ var Analyzer = class _Analyzer {
13610
13758
  )
13611
13759
  );
13612
13760
  } else if (!permissive.includes(functionName)) {
13613
- const expectedTypes = funcDef.signatures.map((sig) => sig.input ? sig.input.singleton ? sig.input.type : `${sig.input.type}[]` : "Any").filter((v, i, a) => a.indexOf(v) === i).join(" or ");
13761
+ const expectedTypes = funcDef.signatures.map((sig) => {
13762
+ if (!sig.input) return "Any";
13763
+ const name = sig.input.name || sig.input.type;
13764
+ return sig.input.singleton ? name : `${name}[]`;
13765
+ }).filter((v, i, a) => a.indexOf(v) === i).join(" or ");
13614
13766
  diagnostics.push(
13615
13767
  this.createError(
13616
13768
  node,
@@ -14022,6 +14174,10 @@ var Analyzer = class _Analyzer {
14022
14174
  this.cursorMode = options?.cursorMode ?? false;
14023
14175
  this.stoppedAtCursor = false;
14024
14176
  this.cursorContext = void 0;
14177
+ if (this.modelProvider && this.resourceTypesCache === null) {
14178
+ const list = await this.modelProvider.getResourceTypes();
14179
+ this.resourceTypesCache = new Set(list);
14180
+ }
14025
14181
  const systemVars = /* @__PURE__ */ new Map();
14026
14182
  systemVars.set("$this", inputType || { type: "Any", singleton: false });
14027
14183
  systemVars.set("$index", { type: "Integer", singleton: true });
@@ -14938,10 +15094,33 @@ async function provideCompletions(expression, cursorPosition, options = {}) {
14938
15094
  return [];
14939
15095
  }
14940
15096
  }
14941
- function isFunctionApplicable(funcDef, typeInfo) {
15097
+ async function isFunctionApplicable(funcDef, typeInfo, modelProvider) {
14942
15098
  if (!typeInfo || !typeInfo.type) return true;
14943
15099
  const typeForRegistry = typeInfo.singleton === false ? `${typeInfo.type}[]` : typeInfo.type;
14944
- return registry.isFunctionApplicableToType(funcDef.name, typeForRegistry);
15100
+ if (!registry.isFunctionApplicableToType(funcDef.name, typeForRegistry)) {
15101
+ return false;
15102
+ }
15103
+ if (funcDef.signatures) {
15104
+ const hasNameConstraint = funcDef.signatures.some(
15105
+ (sig) => sig.input && sig.input.name
15106
+ );
15107
+ if (hasNameConstraint && typeInfo.name) {
15108
+ const resourceTypes = modelProvider ? await modelProvider.getResourceTypes() : [];
15109
+ const nameMatches = funcDef.signatures.some((sig) => {
15110
+ if (!sig.input?.name) return true;
15111
+ if (sig.input.name === typeInfo.name) return true;
15112
+ if (sig.input.name === "Resource") {
15113
+ const name = typeInfo.name;
15114
+ return name === "Resource" || name !== void 0 && resourceTypes.includes(name);
15115
+ }
15116
+ return false;
15117
+ });
15118
+ if (!nameMatches) {
15119
+ return false;
15120
+ }
15121
+ }
15122
+ }
15123
+ return true;
14945
15124
  }
14946
15125
  function isOperatorApplicable(opDef, typeInfo) {
14947
15126
  if (!typeInfo || !typeInfo.type) return true;
@@ -14985,7 +15164,7 @@ async function getIdentifierCompletions(typeBeforeCursor, modelProvider) {
14985
15164
  for (const name of functionNames) {
14986
15165
  const funcDef = registry.getFunction(name);
14987
15166
  if (funcDef) {
14988
- const isApplicable = !typeBeforeCursor || isFunctionApplicable(funcDef, typeBeforeCursor);
15167
+ const isApplicable = !typeBeforeCursor || await isFunctionApplicable(funcDef, typeBeforeCursor, modelProvider);
14989
15168
  if (isApplicable) {
14990
15169
  const hasParams = funcDef.signatures?.some((sig) => (sig.parameters?.length ?? 0) > 0) ?? false;
14991
15170
  const funcDescription = funcDef.description || `FHIRPath ${name} function`;
@@ -15002,7 +15181,7 @@ async function getIdentifierCompletions(typeBeforeCursor, modelProvider) {
15002
15181
  const typeForRegistry = typeBeforeCursor.singleton === false ? `${typeBeforeCursor.type}[]` : typeBeforeCursor.type;
15003
15182
  const typeFunctions = registry.getFunctionsForType(typeForRegistry);
15004
15183
  for (const func of typeFunctions) {
15005
- if (!completions.some((c) => c.label === func.name)) {
15184
+ if (!completions.some((c) => c.label === func.name) && await isFunctionApplicable(func, typeBeforeCursor, modelProvider)) {
15006
15185
  const hasParams = func.signatures?.some((sig) => (sig.parameters?.length ?? 0) > 0) ?? false;
15007
15186
  completions.push({
15008
15187
  label: func.name,
@@ -15245,7 +15424,7 @@ function rankCompletions(completions) {
15245
15424
  }
15246
15425
 
15247
15426
  // src/index.common.ts
15248
- async function evaluate106(expression, options = {}) {
15427
+ async function evaluate108(expression, options = {}) {
15249
15428
  const interpreter = new Interpreter(void 0, options.modelProvider);
15250
15429
  return interpreter.evaluateExpression(expression, {
15251
15430
  input: options.input,
@@ -15265,7 +15444,7 @@ async function analyze(expression, options = {}) {
15265
15444
  return analysisResult;
15266
15445
  }
15267
15446
  function getVersion() {
15268
- return "0.0.5";
15447
+ return "0.1.0-canary.20260203155750.e52d2f6";
15269
15448
  }
15270
15449
  var FHIRModelProviderBase = class _FHIRModelProviderBase {
15271
15450
  constructor() {
@@ -15347,23 +15526,19 @@ var FHIRModelProviderBase = class _FHIRModelProviderBase {
15347
15526
  this.initialized = true;
15348
15527
  }
15349
15528
  }
15350
- async resolve(_canonicalUrl) {
15529
+ async resolve(_typeName) {
15351
15530
  throw new Error("Resolve not implemented.");
15352
15531
  }
15353
15532
  async search(_params) {
15354
15533
  throw new Error("Search not implemented.");
15355
15534
  }
15356
- buildCanonicalUrl(typeName) {
15357
- return `http://hl7.org/fhir/StructureDefinition/${typeName}`;
15358
- }
15359
15535
  // Public method to get schema with automatic caching
15360
15536
  async getSchema(typeName) {
15361
15537
  if (this.schemaCache.has(typeName)) {
15362
15538
  return this.schemaCache.get(typeName);
15363
15539
  }
15364
15540
  try {
15365
- const canonicalUrl = this.buildCanonicalUrl(typeName);
15366
- const resource = await this.resolve(canonicalUrl);
15541
+ const resource = await this.resolve(typeName);
15367
15542
  if (!resource || resource.resourceType !== "StructureDefinition") {
15368
15543
  return void 0;
15369
15544
  }
@@ -15752,14 +15927,16 @@ var FHIRModelProvider = class extends FHIRModelProviderBase {
15752
15927
  async prepare() {
15753
15928
  await this.canonicalManager.init();
15754
15929
  }
15755
- async resolve(canonicalUrl) {
15756
- return await this.canonicalManager.resolve(canonicalUrl);
15930
+ async resolve(typeName) {
15931
+ return await this.canonicalManager.resolve(
15932
+ `http://hl7.org/fhir/StructureDefinition/${typeName}`
15933
+ );
15757
15934
  }
15758
15935
  async search(params) {
15759
15936
  return await this.canonicalManager.search(params);
15760
15937
  }
15761
15938
  };
15762
15939
 
15763
- export { Analyzer, CompletionKind, CursorContext, DiagnosticSeverity, ErrorCodes, Errors, FHIRModelProvider, FHIRPathError, Interpreter, Parser, Registry, analyze, evaluate106 as evaluate, getVersion, inspect, isCursorNode, parse, provideCompletions, registry };
15940
+ export { Analyzer, CompletionKind, CursorContext, DiagnosticSeverity, ErrorCodes, Errors, FHIRModelProvider, FHIRPathError, Interpreter, Parser, Registry, analyze, evaluate108 as evaluate, getVersion, inspect, isCursorNode, parse, provideCompletions, registry };
15764
15941
  //# sourceMappingURL=index.node.js.map
15765
15942
  //# sourceMappingURL=index.node.js.map