@peerbits/fhir-validator 1.0.0 → 1.0.1

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.
package/README.md CHANGED
@@ -49,7 +49,9 @@ npm install @peerbits/fhir-validator
49
49
 
50
50
  ---
51
51
 
52
- ## Quick Start
52
+ ## Demo and Quick Start
53
+
54
+ [Peerbits HealthTech - Fhir Validator Demo](https://healthcare.peerbits.com/demo/fhir-validator)
53
55
 
54
56
  ### 1. Validating a Resource
55
57
 
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 ClaimResponse resource.
4
+ */
5
+ export declare function validateClaimResponse(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,186 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ const VALID_CLAIM_RESPONSE_STATUSES = ["active", "cancelled", "draft", "entered-in-error"];
4
+ const VALID_CLAIM_RESPONSE_USES = ["claim", "preauthorization", "predetermination"];
5
+ const VALID_CLAIM_RESPONSE_OUTCOMES = ["queued", "complete", "error", "partial"];
6
+ /**
7
+ * Validates base structural rules for FHIR R4 ClaimResponse resource.
8
+ */
9
+ export function validateClaimResponse(resource, path = "ClaimResponse") {
10
+ const issues = [];
11
+ if (resource.resourceType !== "ClaimResponse") {
12
+ issues.push({
13
+ severity: "error",
14
+ path: `${path}.resourceType`,
15
+ code: "invalid-resource-type",
16
+ message: `Expected resourceType 'ClaimResponse', found '${String(resource.resourceType)}'.`,
17
+ });
18
+ }
19
+ // status (Required)
20
+ if (resource.status === undefined || resource.status === null || resource.status === "") {
21
+ issues.push({
22
+ severity: "error",
23
+ path: `${path}.status`,
24
+ code: "required",
25
+ message: `Missing required 'status' in '${path}'.`,
26
+ });
27
+ }
28
+ else if (typeof resource.status !== "string" || !VALID_CLAIM_RESPONSE_STATUSES.includes(resource.status)) {
29
+ issues.push({
30
+ severity: "error",
31
+ path: `${path}.status`,
32
+ code: "invalid-value",
33
+ message: `Invalid ClaimResponse status '${String(resource.status)}'. Allowed values: ${VALID_CLAIM_RESPONSE_STATUSES.join(", ")}.`,
34
+ });
35
+ }
36
+ // type (Required CodeableConcept)
37
+ if (resource.type === undefined || resource.type === null) {
38
+ issues.push({
39
+ severity: "error",
40
+ path: `${path}.type`,
41
+ code: "required",
42
+ message: `Missing required 'type' in '${path}'.`,
43
+ });
44
+ }
45
+ else {
46
+ issues.push(...validateCodeableConcept(resource.type, `${path}.type`));
47
+ }
48
+ // use (Required enum: claim | preauthorization | predetermination)
49
+ if (resource.use === undefined || resource.use === null || resource.use === "") {
50
+ issues.push({
51
+ severity: "error",
52
+ path: `${path}.use`,
53
+ code: "required",
54
+ message: `Missing required 'use' in '${path}'.`,
55
+ });
56
+ }
57
+ else if (typeof resource.use !== "string" || !VALID_CLAIM_RESPONSE_USES.includes(resource.use)) {
58
+ issues.push({
59
+ severity: "error",
60
+ path: `${path}.use`,
61
+ code: "invalid-value",
62
+ message: `Invalid ClaimResponse use '${String(resource.use)}'. Allowed values: ${VALID_CLAIM_RESPONSE_USES.join(", ")}.`,
63
+ });
64
+ }
65
+ // patient (Required Reference: Patient)
66
+ if (resource.patient === undefined || resource.patient === null) {
67
+ issues.push({
68
+ severity: "error",
69
+ path: `${path}.patient`,
70
+ code: "required",
71
+ message: `Missing required 'patient' in '${path}'.`,
72
+ });
73
+ }
74
+ else {
75
+ issues.push(...validateReference(resource.patient, `${path}.patient`, ["Patient"]));
76
+ }
77
+ // created (Required string dateTime)
78
+ if (resource.created === undefined || resource.created === null || resource.created === "") {
79
+ issues.push({
80
+ severity: "error",
81
+ path: `${path}.created`,
82
+ code: "required",
83
+ message: `Missing required 'created' in '${path}'.`,
84
+ });
85
+ }
86
+ else if (typeof resource.created !== "string") {
87
+ issues.push({
88
+ severity: "error",
89
+ path: `${path}.created`,
90
+ code: "invalid-type",
91
+ message: `Expected '${path}.created' to be a string dateTime.`,
92
+ });
93
+ }
94
+ // insurer (Required Reference: Organization)
95
+ if (resource.insurer === undefined || resource.insurer === null) {
96
+ issues.push({
97
+ severity: "error",
98
+ path: `${path}.insurer`,
99
+ code: "required",
100
+ message: `Missing required 'insurer' in '${path}'.`,
101
+ });
102
+ }
103
+ else {
104
+ issues.push(...validateReference(resource.insurer, `${path}.insurer`, ["Organization"]));
105
+ }
106
+ // outcome (Required enum: queued | complete | error | partial)
107
+ if (resource.outcome === undefined || resource.outcome === null || resource.outcome === "") {
108
+ issues.push({
109
+ severity: "error",
110
+ path: `${path}.outcome`,
111
+ code: "required",
112
+ message: `Missing required 'outcome' in '${path}'.`,
113
+ });
114
+ }
115
+ else if (typeof resource.outcome !== "string" || !VALID_CLAIM_RESPONSE_OUTCOMES.includes(resource.outcome)) {
116
+ issues.push({
117
+ severity: "error",
118
+ path: `${path}.outcome`,
119
+ code: "invalid-value",
120
+ message: `Invalid ClaimResponse outcome '${String(resource.outcome)}'. Allowed values: ${VALID_CLAIM_RESPONSE_OUTCOMES.join(", ")}.`,
121
+ });
122
+ }
123
+ // request (Reference: Claim)
124
+ if (resource.request !== undefined) {
125
+ issues.push(...validateReference(resource.request, `${path}.request`, ["Claim"]));
126
+ }
127
+ // requestor (Reference: Practitioner | PractitionerRole | Organization)
128
+ if (resource.requestor !== undefined) {
129
+ issues.push(...validateReference(resource.requestor, `${path}.requestor`, ["Practitioner", "PractitionerRole", "Organization"]));
130
+ }
131
+ // insurance (Array)
132
+ if (resource.insurance !== undefined) {
133
+ if (!Array.isArray(resource.insurance)) {
134
+ issues.push({
135
+ severity: "error",
136
+ path: `${path}.insurance`,
137
+ code: "invalid-type",
138
+ message: `Expected '${path}.insurance' to be an array.`,
139
+ });
140
+ }
141
+ else {
142
+ resource.insurance.forEach((ins, idx) => {
143
+ const insPath = `${path}.insurance[${idx}]`;
144
+ if (typeof ins !== "object" || ins === null || Array.isArray(ins)) {
145
+ issues.push({
146
+ severity: "error",
147
+ path: insPath,
148
+ code: "invalid-structure",
149
+ message: `Expected '${insPath}' to be an object.`,
150
+ });
151
+ }
152
+ else {
153
+ const obj = ins;
154
+ if (typeof obj.sequence !== "number") {
155
+ issues.push({
156
+ severity: "error",
157
+ path: `${insPath}.sequence`,
158
+ code: "required",
159
+ message: `Missing or invalid 'sequence' number in '${insPath}'.`,
160
+ });
161
+ }
162
+ if (typeof obj.focal !== "boolean") {
163
+ issues.push({
164
+ severity: "error",
165
+ path: `${insPath}.focal`,
166
+ code: "required",
167
+ message: `Missing or invalid 'focal' boolean in '${insPath}'.`,
168
+ });
169
+ }
170
+ if (obj.coverage === undefined || obj.coverage === null) {
171
+ issues.push({
172
+ severity: "error",
173
+ path: `${insPath}.coverage`,
174
+ code: "required",
175
+ message: `Missing required 'coverage' reference in '${insPath}'.`,
176
+ });
177
+ }
178
+ else {
179
+ issues.push(...validateReference(obj.coverage, `${insPath}.coverage`, ["Coverage"]));
180
+ }
181
+ }
182
+ });
183
+ }
184
+ }
185
+ return issues;
186
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Claim resource.
4
+ */
5
+ export declare function validateClaim(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,240 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ const VALID_CLAIM_STATUSES = ["active", "cancelled", "draft", "entered-in-error"];
4
+ const VALID_CLAIM_USES = ["claim", "preauthorization", "predetermination"];
5
+ /**
6
+ * Validates base structural rules for FHIR R4 Claim resource.
7
+ */
8
+ export function validateClaim(resource, path = "Claim") {
9
+ const issues = [];
10
+ if (resource.resourceType !== "Claim") {
11
+ issues.push({
12
+ severity: "error",
13
+ path: `${path}.resourceType`,
14
+ code: "invalid-resource-type",
15
+ message: `Expected resourceType 'Claim', found '${String(resource.resourceType)}'.`,
16
+ });
17
+ }
18
+ // status (Required)
19
+ if (resource.status === undefined || resource.status === null || resource.status === "") {
20
+ issues.push({
21
+ severity: "error",
22
+ path: `${path}.status`,
23
+ code: "required",
24
+ message: `Missing required 'status' in '${path}'.`,
25
+ });
26
+ }
27
+ else if (typeof resource.status !== "string" || !VALID_CLAIM_STATUSES.includes(resource.status)) {
28
+ issues.push({
29
+ severity: "error",
30
+ path: `${path}.status`,
31
+ code: "invalid-value",
32
+ message: `Invalid Claim status '${String(resource.status)}'. Allowed values: ${VALID_CLAIM_STATUSES.join(", ")}.`,
33
+ });
34
+ }
35
+ // type (Required CodeableConcept)
36
+ if (resource.type === undefined || resource.type === null) {
37
+ issues.push({
38
+ severity: "error",
39
+ path: `${path}.type`,
40
+ code: "required",
41
+ message: `Missing required 'type' in '${path}'.`,
42
+ });
43
+ }
44
+ else {
45
+ issues.push(...validateCodeableConcept(resource.type, `${path}.type`));
46
+ }
47
+ // use (Required enum: claim | preauthorization | predetermination)
48
+ if (resource.use === undefined || resource.use === null || resource.use === "") {
49
+ issues.push({
50
+ severity: "error",
51
+ path: `${path}.use`,
52
+ code: "required",
53
+ message: `Missing required 'use' in '${path}'.`,
54
+ });
55
+ }
56
+ else if (typeof resource.use !== "string" || !VALID_CLAIM_USES.includes(resource.use)) {
57
+ issues.push({
58
+ severity: "error",
59
+ path: `${path}.use`,
60
+ code: "invalid-value",
61
+ message: `Invalid Claim use '${String(resource.use)}'. Allowed values: ${VALID_CLAIM_USES.join(", ")}.`,
62
+ });
63
+ }
64
+ // patient (Required Reference: Patient)
65
+ if (resource.patient === undefined || resource.patient === null) {
66
+ issues.push({
67
+ severity: "error",
68
+ path: `${path}.patient`,
69
+ code: "required",
70
+ message: `Missing required 'patient' in '${path}'.`,
71
+ });
72
+ }
73
+ else {
74
+ issues.push(...validateReference(resource.patient, `${path}.patient`, ["Patient"]));
75
+ }
76
+ // created (Required string dateTime)
77
+ if (resource.created === undefined || resource.created === null || resource.created === "") {
78
+ issues.push({
79
+ severity: "error",
80
+ path: `${path}.created`,
81
+ code: "required",
82
+ message: `Missing required 'created' in '${path}'.`,
83
+ });
84
+ }
85
+ else if (typeof resource.created !== "string") {
86
+ issues.push({
87
+ severity: "error",
88
+ path: `${path}.created`,
89
+ code: "invalid-type",
90
+ message: `Expected '${path}.created' to be a string dateTime.`,
91
+ });
92
+ }
93
+ // provider (Required Reference: Practitioner | PractitionerRole | Organization)
94
+ if (resource.provider === undefined || resource.provider === null) {
95
+ issues.push({
96
+ severity: "error",
97
+ path: `${path}.provider`,
98
+ code: "required",
99
+ message: `Missing required 'provider' in '${path}'.`,
100
+ });
101
+ }
102
+ else {
103
+ issues.push(...validateReference(resource.provider, `${path}.provider`, ["Practitioner", "PractitionerRole", "Organization"]));
104
+ }
105
+ // priority (Required CodeableConcept)
106
+ if (resource.priority === undefined || resource.priority === null) {
107
+ issues.push({
108
+ severity: "error",
109
+ path: `${path}.priority`,
110
+ code: "required",
111
+ message: `Missing required 'priority' in '${path}'.`,
112
+ });
113
+ }
114
+ else {
115
+ issues.push(...validateCodeableConcept(resource.priority, `${path}.priority`));
116
+ }
117
+ // insurer (Reference: Organization)
118
+ if (resource.insurer !== undefined) {
119
+ issues.push(...validateReference(resource.insurer, `${path}.insurer`, ["Organization"]));
120
+ }
121
+ // facility (Reference: Location)
122
+ if (resource.facility !== undefined) {
123
+ issues.push(...validateReference(resource.facility, `${path}.facility`, ["Location"]));
124
+ }
125
+ // insurance (Required array, min 1)
126
+ if (resource.insurance === undefined || resource.insurance === null) {
127
+ issues.push({
128
+ severity: "error",
129
+ path: `${path}.insurance`,
130
+ code: "required",
131
+ message: `Missing required 'insurance' in '${path}'.`,
132
+ });
133
+ }
134
+ else if (!Array.isArray(resource.insurance)) {
135
+ issues.push({
136
+ severity: "error",
137
+ path: `${path}.insurance`,
138
+ code: "invalid-type",
139
+ message: `Expected '${path}.insurance' to be an array, got ${typeof resource.insurance}.`,
140
+ });
141
+ }
142
+ else if (resource.insurance.length === 0) {
143
+ issues.push({
144
+ severity: "error",
145
+ path: `${path}.insurance`,
146
+ code: "cardinality",
147
+ message: `Expected at least 1 insurance element in '${path}.insurance', found 0.`,
148
+ });
149
+ }
150
+ else {
151
+ resource.insurance.forEach((ins, idx) => {
152
+ const insPath = `${path}.insurance[${idx}]`;
153
+ if (typeof ins !== "object" || ins === null || Array.isArray(ins)) {
154
+ issues.push({
155
+ severity: "error",
156
+ path: insPath,
157
+ code: "invalid-structure",
158
+ message: `Expected '${insPath}' to be an object.`,
159
+ });
160
+ }
161
+ else {
162
+ const obj = ins;
163
+ if (typeof obj.sequence !== "number") {
164
+ issues.push({
165
+ severity: "error",
166
+ path: `${insPath}.sequence`,
167
+ code: "required",
168
+ message: `Missing or invalid 'sequence' number in '${insPath}'.`,
169
+ });
170
+ }
171
+ if (typeof obj.focal !== "boolean") {
172
+ issues.push({
173
+ severity: "error",
174
+ path: `${insPath}.focal`,
175
+ code: "required",
176
+ message: `Missing or invalid 'focal' boolean in '${insPath}'.`,
177
+ });
178
+ }
179
+ if (obj.coverage === undefined || obj.coverage === null) {
180
+ issues.push({
181
+ severity: "error",
182
+ path: `${insPath}.coverage`,
183
+ code: "required",
184
+ message: `Missing required 'coverage' reference in '${insPath}'.`,
185
+ });
186
+ }
187
+ else {
188
+ issues.push(...validateReference(obj.coverage, `${insPath}.coverage`, ["Coverage"]));
189
+ }
190
+ }
191
+ });
192
+ }
193
+ // item (Array)
194
+ if (resource.item !== undefined) {
195
+ if (!Array.isArray(resource.item)) {
196
+ issues.push({
197
+ severity: "error",
198
+ path: `${path}.item`,
199
+ code: "invalid-type",
200
+ message: `Expected '${path}.item' to be an array, got ${typeof resource.item}.`,
201
+ });
202
+ }
203
+ else {
204
+ resource.item.forEach((it, idx) => {
205
+ const itPath = `${path}.item[${idx}]`;
206
+ if (typeof it !== "object" || it === null || Array.isArray(it)) {
207
+ issues.push({
208
+ severity: "error",
209
+ path: itPath,
210
+ code: "invalid-structure",
211
+ message: `Expected '${itPath}' to be an object.`,
212
+ });
213
+ }
214
+ else {
215
+ const itemObj = it;
216
+ if (typeof itemObj.sequence !== "number") {
217
+ issues.push({
218
+ severity: "error",
219
+ path: `${itPath}.sequence`,
220
+ code: "required",
221
+ message: `Missing or invalid 'sequence' number in '${itPath}'.`,
222
+ });
223
+ }
224
+ if (itemObj.productOrService === undefined || itemObj.productOrService === null) {
225
+ issues.push({
226
+ severity: "error",
227
+ path: `${itPath}.productOrService`,
228
+ code: "required",
229
+ message: `Missing required 'productOrService' in '${itPath}'.`,
230
+ });
231
+ }
232
+ else {
233
+ issues.push(...validateCodeableConcept(itemObj.productOrService, `${itPath}.productOrService`));
234
+ }
235
+ }
236
+ });
237
+ }
238
+ }
239
+ return issues;
240
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Condition resource.
4
+ */
5
+ export declare function validateCondition(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,78 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ /**
4
+ * Validates base structural rules for FHIR R4 Condition resource.
5
+ */
6
+ export function validateCondition(resource, path = "Condition") {
7
+ const issues = [];
8
+ if (resource.resourceType !== "Condition") {
9
+ issues.push({
10
+ severity: "error",
11
+ path: `${path}.resourceType`,
12
+ code: "invalid-resource-type",
13
+ message: `Expected resourceType 'Condition', found '${String(resource.resourceType)}'.`,
14
+ });
15
+ }
16
+ // subject (Required Reference: Patient | Group)
17
+ if (resource.subject === undefined || resource.subject === null) {
18
+ issues.push({
19
+ severity: "error",
20
+ path: `${path}.subject`,
21
+ code: "required",
22
+ message: `Missing required 'subject' in '${path}'.`,
23
+ });
24
+ }
25
+ else {
26
+ issues.push(...validateReference(resource.subject, `${path}.subject`, ["Patient", "Group"]));
27
+ }
28
+ // clinicalStatus (CodeableConcept)
29
+ if (resource.clinicalStatus !== undefined) {
30
+ issues.push(...validateCodeableConcept(resource.clinicalStatus, `${path}.clinicalStatus`));
31
+ }
32
+ // verificationStatus (CodeableConcept)
33
+ if (resource.verificationStatus !== undefined) {
34
+ issues.push(...validateCodeableConcept(resource.verificationStatus, `${path}.verificationStatus`));
35
+ }
36
+ // category (CodeableConcept[])
37
+ if (resource.category !== undefined) {
38
+ if (!Array.isArray(resource.category)) {
39
+ issues.push({
40
+ severity: "error",
41
+ path: `${path}.category`,
42
+ code: "invalid-type",
43
+ message: `Expected '${path}.category' to be an array, got ${typeof resource.category}.`,
44
+ });
45
+ }
46
+ else {
47
+ resource.category.forEach((cat, idx) => {
48
+ issues.push(...validateCodeableConcept(cat, `${path}.category[${idx}]`));
49
+ });
50
+ }
51
+ }
52
+ // code (CodeableConcept)
53
+ if (resource.code !== undefined) {
54
+ issues.push(...validateCodeableConcept(resource.code, `${path}.code`));
55
+ }
56
+ // encounter (Reference: Encounter)
57
+ if (resource.encounter !== undefined) {
58
+ issues.push(...validateReference(resource.encounter, `${path}.encounter`, ["Encounter"]));
59
+ }
60
+ // recorder (Reference)
61
+ if (resource.recorder !== undefined) {
62
+ issues.push(...validateReference(resource.recorder, `${path}.recorder`, ["Practitioner", "PractitionerRole", "Patient", "RelatedPerson"]));
63
+ }
64
+ // asserter (Reference)
65
+ if (resource.asserter !== undefined) {
66
+ issues.push(...validateReference(resource.asserter, `${path}.asserter`, ["Practitioner", "PractitionerRole", "Patient", "RelatedPerson"]));
67
+ }
68
+ // recordedDate
69
+ if (resource.recordedDate !== undefined && typeof resource.recordedDate !== "string") {
70
+ issues.push({
71
+ severity: "error",
72
+ path: `${path}.recordedDate`,
73
+ code: "invalid-type",
74
+ message: `Expected '${path}.recordedDate' to be a string.`,
75
+ });
76
+ }
77
+ return issues;
78
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Coverage resource.
4
+ */
5
+ export declare function validateCoverage(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,109 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ const VALID_COVERAGE_STATUSES = ["active", "cancelled", "draft", "entered-in-error"];
4
+ /**
5
+ * Validates base structural rules for FHIR R4 Coverage resource.
6
+ */
7
+ export function validateCoverage(resource, path = "Coverage") {
8
+ const issues = [];
9
+ if (resource.resourceType !== "Coverage") {
10
+ issues.push({
11
+ severity: "error",
12
+ path: `${path}.resourceType`,
13
+ code: "invalid-resource-type",
14
+ message: `Expected resourceType 'Coverage', found '${String(resource.resourceType)}'.`,
15
+ });
16
+ }
17
+ // status (Required)
18
+ if (resource.status === undefined || resource.status === null || resource.status === "") {
19
+ issues.push({
20
+ severity: "error",
21
+ path: `${path}.status`,
22
+ code: "required",
23
+ message: `Missing required 'status' in '${path}'.`,
24
+ });
25
+ }
26
+ else if (typeof resource.status !== "string" || !VALID_COVERAGE_STATUSES.includes(resource.status)) {
27
+ issues.push({
28
+ severity: "error",
29
+ path: `${path}.status`,
30
+ code: "invalid-value",
31
+ message: `Invalid Coverage status '${String(resource.status)}'. Allowed values: ${VALID_COVERAGE_STATUSES.join(", ")}.`,
32
+ });
33
+ }
34
+ // beneficiary (Required Reference: Patient)
35
+ if (resource.beneficiary === undefined || resource.beneficiary === null) {
36
+ issues.push({
37
+ severity: "error",
38
+ path: `${path}.beneficiary`,
39
+ code: "required",
40
+ message: `Missing required 'beneficiary' in '${path}'.`,
41
+ });
42
+ }
43
+ else {
44
+ issues.push(...validateReference(resource.beneficiary, `${path}.beneficiary`, ["Patient"]));
45
+ }
46
+ // payor (Required Reference[]: Organization | Patient | RelatedPerson, min 1)
47
+ if (resource.payor === undefined || resource.payor === null) {
48
+ issues.push({
49
+ severity: "error",
50
+ path: `${path}.payor`,
51
+ code: "required",
52
+ message: `Missing required 'payor' in '${path}'.`,
53
+ });
54
+ }
55
+ else if (!Array.isArray(resource.payor)) {
56
+ issues.push({
57
+ severity: "error",
58
+ path: `${path}.payor`,
59
+ code: "invalid-type",
60
+ message: `Expected '${path}.payor' to be an array, got ${typeof resource.payor}.`,
61
+ });
62
+ }
63
+ else if (resource.payor.length === 0) {
64
+ issues.push({
65
+ severity: "error",
66
+ path: `${path}.payor`,
67
+ code: "cardinality",
68
+ message: `Expected at least 1 payor in '${path}.payor', found 0.`,
69
+ });
70
+ }
71
+ else {
72
+ resource.payor.forEach((p, idx) => {
73
+ issues.push(...validateReference(p, `${path}.payor[${idx}]`, ["Organization", "Patient", "RelatedPerson"]));
74
+ });
75
+ }
76
+ // subscriber (Reference: Patient | RelatedPerson)
77
+ if (resource.subscriber !== undefined) {
78
+ issues.push(...validateReference(resource.subscriber, `${path}.subscriber`, ["Patient", "RelatedPerson"]));
79
+ }
80
+ // subscriberId (string)
81
+ if (resource.subscriberId !== undefined && typeof resource.subscriberId !== "string") {
82
+ issues.push({
83
+ severity: "error",
84
+ path: `${path}.subscriberId`,
85
+ code: "invalid-type",
86
+ message: `Expected '${path}.subscriberId' to be a string.`,
87
+ });
88
+ }
89
+ // type (CodeableConcept)
90
+ if (resource.type !== undefined) {
91
+ issues.push(...validateCodeableConcept(resource.type, `${path}.type`));
92
+ }
93
+ // relationship (CodeableConcept)
94
+ if (resource.relationship !== undefined) {
95
+ issues.push(...validateCodeableConcept(resource.relationship, `${path}.relationship`));
96
+ }
97
+ // period (Period)
98
+ if (resource.period !== undefined) {
99
+ if (typeof resource.period !== "object" || resource.period === null || Array.isArray(resource.period)) {
100
+ issues.push({
101
+ severity: "error",
102
+ path: `${path}.period`,
103
+ code: "invalid-structure",
104
+ message: `Expected '${path}.period' to be an object.`,
105
+ });
106
+ }
107
+ }
108
+ return issues;
109
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Encounter resource.
4
+ */
5
+ export declare function validateEncounter(resource: Record<string, unknown>, path?: string): ValidationIssue[];