fhirpath-ts 0.2.0 → 0.2.2

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.
Files changed (83) hide show
  1. package/README.md +12 -5
  2. package/dist/analyzer/analyze-dto.d.ts.map +1 -1
  3. package/dist/analyzer/analyze-dto.js +14 -8
  4. package/dist/analyzer/analyze-dto.js.map +1 -1
  5. package/dist/analyzer/analyze.d.ts +23 -12
  6. package/dist/analyzer/analyze.d.ts.map +1 -1
  7. package/dist/analyzer/analyze.js +138 -46
  8. package/dist/analyzer/analyze.js.map +1 -1
  9. package/dist/analyzer/declarations.d.ts +6 -0
  10. package/dist/analyzer/declarations.d.ts.map +1 -1
  11. package/dist/analyzer/declarations.js +7 -0
  12. package/dist/analyzer/declarations.js.map +1 -1
  13. package/dist/analyzer/expression-policy.d.ts +88 -14
  14. package/dist/analyzer/expression-policy.d.ts.map +1 -1
  15. package/dist/analyzer/expression-policy.js +296 -41
  16. package/dist/analyzer/expression-policy.js.map +1 -1
  17. package/dist/analyzer/operator-rules.d.ts.map +1 -1
  18. package/dist/analyzer/operator-rules.js +7 -6
  19. package/dist/analyzer/operator-rules.js.map +1 -1
  20. package/dist/analyzer/signatures.d.ts +49 -0
  21. package/dist/analyzer/signatures.d.ts.map +1 -1
  22. package/dist/analyzer/signatures.js +76 -31
  23. package/dist/analyzer/signatures.js.map +1 -1
  24. package/dist/analyzer/source-options.d.ts +17 -0
  25. package/dist/analyzer/source-options.d.ts.map +1 -0
  26. package/dist/analyzer/source-options.js +3 -0
  27. package/dist/analyzer/source-options.js.map +1 -0
  28. package/dist/api/dto.d.ts +9 -4
  29. package/dist/api/dto.d.ts.map +1 -1
  30. package/dist/api/dto.js +14 -3
  31. package/dist/api/dto.js.map +1 -1
  32. package/dist/api/strict.d.ts.map +1 -1
  33. package/dist/api/strict.js +8 -3
  34. package/dist/api/strict.js.map +1 -1
  35. package/dist/cli/dto-check.d.ts +9 -0
  36. package/dist/cli/dto-check.d.ts.map +1 -1
  37. package/dist/cli/dto-check.js +49 -6
  38. package/dist/cli/dto-check.js.map +1 -1
  39. package/dist/cli/fhirpath-check.js +161 -31
  40. package/dist/cli/fhirpath-check.js.map +1 -1
  41. package/dist/eslint/index.d.ts.map +1 -1
  42. package/dist/eslint/index.js +13 -8
  43. package/dist/eslint/index.js.map +1 -1
  44. package/dist/r4/generated/resources-data.d.ts +6 -2
  45. package/dist/r4/generated/resources-data.d.ts.map +1 -1
  46. package/dist/r4/generated/resources-data.js +626 -28627
  47. package/dist/r4/generated/resources-data.js.map +1 -1
  48. package/dist/r4/generated/types-data.d.ts +6 -2
  49. package/dist/r4/generated/types-data.d.ts.map +1 -1
  50. package/dist/r4/generated/types-data.js +84 -2204
  51. package/dist/r4/generated/types-data.js.map +1 -1
  52. package/dist/r4/index.d.ts.map +1 -1
  53. package/dist/r4/index.js +10 -4
  54. package/dist/r4/index.js.map +1 -1
  55. package/dist/r4/model-data.d.ts +17 -0
  56. package/dist/r4/model-data.d.ts.map +1 -1
  57. package/dist/r4/model-data.js +118 -1
  58. package/dist/r4/model-data.js.map +1 -1
  59. package/dist/sites/index.d.ts +31 -2
  60. package/dist/sites/index.d.ts.map +1 -1
  61. package/dist/sites/index.js +351 -30
  62. package/dist/sites/index.js.map +1 -1
  63. package/dist/typed/infer.d.ts +2 -0
  64. package/dist/typed/infer.d.ts.map +1 -1
  65. package/package.json +1 -1
  66. package/src/analyzer/analyze-dto.ts +19 -9
  67. package/src/analyzer/analyze.ts +186 -54
  68. package/src/analyzer/declarations.ts +12 -0
  69. package/src/analyzer/expression-policy.ts +423 -47
  70. package/src/analyzer/operator-rules.ts +7 -6
  71. package/src/analyzer/signatures.ts +100 -36
  72. package/src/analyzer/source-options.ts +19 -0
  73. package/src/api/dto.ts +35 -9
  74. package/src/api/strict.ts +8 -3
  75. package/src/cli/dto-check.ts +56 -6
  76. package/src/cli/fhirpath-check.ts +180 -34
  77. package/src/eslint/index.ts +15 -12
  78. package/src/r4/generated/resources-data.ts +624 -28628
  79. package/src/r4/generated/types-data.ts +82 -2205
  80. package/src/r4/index.ts +11 -5
  81. package/src/r4/model-data.ts +127 -0
  82. package/src/sites/index.ts +428 -40
  83. package/src/typed/infer.ts +2 -2
package/src/r4/index.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { FhirPathEngine } from '../api/engine.ts'
2
2
  import type { ElementInfo, ModelProvider } from '../model/provider.ts'
3
- import { R4_RESOURCES } from './generated/resources-data.ts'
4
- import { R4_DATA_TYPES } from './generated/types-data.ts'
5
- import type { GeneratedElement, GeneratedType } from './model-data.ts'
3
+ import { R4_RESOURCES_COMPACT } from './generated/resources-data.ts'
4
+ import { R4_DATA_TYPES_COMPACT } from './generated/types-data.ts'
5
+ import { CompactTypeTable, type GeneratedElement, type GeneratedType } from './model-data.ts'
6
6
 
7
7
  // One canonical FHIR-primitive → System map lives in values/typed-value.ts;
8
8
  // re-exported here because the model subpath is where consumers look for it.
@@ -12,8 +12,11 @@ export type { GeneratedElement, GeneratedType } from './model-data.ts'
12
12
  const NAMESPACE = 'FHIR'
13
13
  const PREFIX = `${NAMESPACE}.`
14
14
 
15
+ const RESOURCES = new CompactTypeTable(R4_RESOURCES_COMPACT)
16
+ const DATA_TYPES = new CompactTypeTable(R4_DATA_TYPES_COMPACT)
17
+
15
18
  function lookupType(name: string): GeneratedType | undefined {
16
- return R4_RESOURCES[name] ?? R4_DATA_TYPES[name]
19
+ return RESOURCES.get(name) ?? DATA_TYPES.get(name)
17
20
  }
18
21
 
19
22
  function localName(canonical: string): string {
@@ -85,7 +88,10 @@ export const r4Model: ModelProvider = {
85
88
  }
86
89
  current = definition.b
87
90
  }
88
- return names
91
+ // The tables carry each inherited element only on the type that declares
92
+ // it, so the walk yields own elements before inherited ones; sorting gives
93
+ // callers one stable order independent of where an element is declared.
94
+ return names.sort()
89
95
  },
90
96
 
91
97
  isSubtypeOf(type: string, base: string): boolean {
@@ -15,3 +15,130 @@ export interface GeneratedType {
15
15
  b?: string
16
16
  e: Record<string, GeneratedElement>
17
17
  }
18
+
19
+ /**
20
+ * The generated tables ship as one compact string instead of an object literal:
21
+ * the string is smaller to download and cheaper to decode than a large literal
22
+ * is to parse, and `CompactTypeTable` decodes one type at a time so only the
23
+ * types an application touches are ever materialized.
24
+ *
25
+ * Format, one line per type:
26
+ *
27
+ * Name|Base|element:type1,type2*^<Target1,Target2;element2:type
28
+ *
29
+ * `*` marks a collection (`a: 1`), `^` a choice element (`c: 1`), and `<`
30
+ * starts the Reference target list (`r`). An empty Base segment means the type
31
+ * has no base. Elements identical to the nearest ancestor's entry are omitted
32
+ * by the generator; lookups walk the base chain (see index.ts).
33
+ */
34
+ const RESERVED_IN_COMPACT = /[|;:,*^<\n\\`$]/
35
+
36
+ function assertCompactSafe(name: string): string {
37
+ if (RESERVED_IN_COMPACT.test(name)) {
38
+ throw new Error(`name contains a character reserved by the compact model encoding: ${name}`)
39
+ }
40
+ return name
41
+ }
42
+
43
+ /** Encodes a generated table into the compact string form (generator-side; see the format above). */
44
+ export function encodeCompactTypes(types: Record<string, GeneratedType>): string {
45
+ const lines: string[] = []
46
+ for (const [name, type] of Object.entries(types)) {
47
+ const elements = Object.entries(type.e).map(([element, info]) => {
48
+ let entry = `${assertCompactSafe(element)}:${info.t.map(assertCompactSafe).join(',')}`
49
+ if (info.a === 1) {
50
+ entry += '*'
51
+ }
52
+ if (info.c === 1) {
53
+ entry += '^'
54
+ }
55
+ if (info.r !== undefined) {
56
+ entry += `<${info.r.map(assertCompactSafe).join(',')}`
57
+ }
58
+ return entry
59
+ })
60
+ lines.push(`${assertCompactSafe(name)}|${assertCompactSafe(type.b ?? '')}|${elements.join(';')}`)
61
+ }
62
+ return lines.join('\n')
63
+ }
64
+
65
+ /** Decodes the segment after the second `|` of a line. */
66
+ function decodeTypeLine(line: string): GeneratedType {
67
+ const baseStart = line.indexOf('|') + 1
68
+ const baseEnd = line.indexOf('|', baseStart)
69
+ const base = line.slice(baseStart, baseEnd)
70
+ const e: Record<string, GeneratedElement> = {}
71
+ const body = line.slice(baseEnd + 1)
72
+ if (body !== '') {
73
+ for (const entry of body.split(';')) {
74
+ const colon = entry.indexOf(':')
75
+ const name = entry.slice(0, colon)
76
+ let rest = entry.slice(colon + 1)
77
+ const element: GeneratedElement = { t: [] }
78
+ const targetsStart = rest.indexOf('<')
79
+ if (targetsStart >= 0) {
80
+ element.r = rest.slice(targetsStart + 1).split(',')
81
+ rest = rest.slice(0, targetsStart)
82
+ }
83
+ if (rest.endsWith('^')) {
84
+ element.c = 1
85
+ rest = rest.slice(0, -1)
86
+ }
87
+ if (rest.endsWith('*')) {
88
+ element.a = 1
89
+ rest = rest.slice(0, -1)
90
+ }
91
+ element.t = rest.split(',')
92
+ e[name] = element
93
+ }
94
+ }
95
+ return base === '' ? { e } : { b: base, e }
96
+ }
97
+
98
+ /** Eagerly decodes a whole table; for build scripts, not the runtime path. */
99
+ export function decodeCompactTypes(encoded: string): Record<string, GeneratedType> {
100
+ const types: Record<string, GeneratedType> = {}
101
+ for (const line of encoded.split('\n')) {
102
+ types[line.slice(0, line.indexOf('|'))] = decodeTypeLine(line)
103
+ }
104
+ return types
105
+ }
106
+
107
+ /**
108
+ * Lazy view over a compact-encoded table. The line index is built on first
109
+ * lookup and each type is decoded once, on demand, so importing the model costs
110
+ * almost nothing until an expression actually navigates it.
111
+ */
112
+ export class CompactTypeTable {
113
+ private readonly encoded: string
114
+ private index: Map<string, string> | undefined
115
+ private readonly decoded = new Map<string, GeneratedType>()
116
+
117
+ constructor(encoded: string) {
118
+ this.encoded = encoded
119
+ }
120
+
121
+ get(name: string): GeneratedType | undefined {
122
+ const cached = this.decoded.get(name)
123
+ if (cached !== undefined) {
124
+ return cached
125
+ }
126
+ const line = this.lines().get(name)
127
+ if (line === undefined) {
128
+ return undefined
129
+ }
130
+ const type = decodeTypeLine(line)
131
+ this.decoded.set(name, type)
132
+ return type
133
+ }
134
+
135
+ private lines(): Map<string, string> {
136
+ if (this.index === undefined) {
137
+ this.index = new Map()
138
+ for (const line of this.encoded.split('\n')) {
139
+ this.index.set(line.slice(0, line.indexOf('|')), line)
140
+ }
141
+ }
142
+ return this.index
143
+ }
144
+ }