|
| 1 | +import type { FixSuggestion } from './types'; |
| 2 | + |
| 3 | +export const CATALOG_REFERENCE_PROFILE: Record<string, FixSuggestion> = { |
| 4 | + // ------------------------------------------------------------------------- |
| 5 | + // Reference |
| 6 | + // ------------------------------------------------------------------------- |
| 7 | + 'reference-not-found': { |
| 8 | + why: 'References should point to existing resources for data integrity.', |
| 9 | + fix: 'Verify the referenced resource exists, or create it before referencing.', |
| 10 | + example: 'subject: { reference: "Patient/123" }', |
| 11 | + }, |
| 12 | + 'reference-type-mismatch': { |
| 13 | + why: 'Reference constraints specify which resource types can be referenced.', |
| 14 | + fix: 'Change the reference to point to an allowed resource type.', |
| 15 | + example: 'Observation.subject should reference Patient, not Practitioner', |
| 16 | + patch: { action: 'replace', path: '{{fieldPath}}.reference', value: '"{{allowed}}/id"' }, |
| 17 | + }, |
| 18 | + 'reference-invalid-format': { |
| 19 | + why: 'FHIR references follow specific formats for routing and resolution.', |
| 20 | + fix: 'Use format: "ResourceType/id" for relative, or full URL for absolute.', |
| 21 | + example: 'reference: "Patient/123" or "https://example.org/fhir/Patient/123"', |
| 22 | + patch: { action: 'replace', path: '{{fieldPath}}.reference', value: '"ResourceType/id"' }, |
| 23 | + }, |
| 24 | + 'reference-empty': { |
| 25 | + why: 'A reference element exists but has no value.', |
| 26 | + fix: 'Add a reference value, or remove the empty reference element.', |
| 27 | + }, |
| 28 | + 'reference-contained-not-found': { |
| 29 | + why: 'The #id reference points to a contained resource that doesn\'t exist.', |
| 30 | + fix: 'Add the resource to the contained array with matching id.', |
| 31 | + example: 'contained: [{ "resourceType": "Organization", "id": "org1", ... }]', |
| 32 | + }, |
| 33 | + 'reference-bundle-unresolved': { |
| 34 | + why: 'Reference within bundle cannot be resolved to any entry.', |
| 35 | + fix: 'Add an entry with matching fullUrl, or use a urn:uuid for temporary IDs.', |
| 36 | + }, |
| 37 | + 'reference-bundle-fullurl-mismatch': { |
| 38 | + why: 'The entry\'s fullUrl doesn\'t match the resource\'s id.', |
| 39 | + fix: 'Ensure fullUrl ends with ResourceType/id matching the resource.', |
| 40 | + }, |
| 41 | + 'reference-bundle-missing-entries': { |
| 42 | + why: 'Bundle requires an entry array.', |
| 43 | + fix: 'Add the entry array with at least one entry.', |
| 44 | + }, |
| 45 | + 'reference-bundle-request-missing-method': { |
| 46 | + why: 'Transaction/batch entries need a request method.', |
| 47 | + fix: 'Add method: "POST" (create), "PUT" (update), "DELETE" (delete), or "GET" (read).', |
| 48 | + }, |
| 49 | + 'reference-bundle-request-missing-url': { |
| 50 | + why: 'Transaction/batch entries need a request URL.', |
| 51 | + fix: 'Add url with the resource path (e.g., "Patient" for POST, "Patient/123" for PUT).', |
| 52 | + }, |
| 53 | + 'reference-invalid-url': { |
| 54 | + why: 'The reference URL is malformed or invalid.', |
| 55 | + fix: 'Use a valid URL format: absolute URL or relative ResourceType/id.', |
| 56 | + }, |
| 57 | + 'reference-invalid-contained': { |
| 58 | + why: 'Contained reference should use #id format.', |
| 59 | + fix: 'Use format: { "reference": "#contained-id" }', |
| 60 | + }, |
| 61 | + 'reference-type-unknown': { |
| 62 | + why: 'Cannot determine the resource type from the reference.', |
| 63 | + fix: 'Include ResourceType in reference (e.g., "Patient/123") or add type field.', |
| 64 | + }, |
| 65 | + 'reference-contained-type-mismatch': { |
| 66 | + why: 'The contained resource type doesn\'t match allowed types.', |
| 67 | + fix: 'Ensure the contained resource type is allowed for this reference.', |
| 68 | + }, |
| 69 | + 'reference-bundle-invalid-entries': { |
| 70 | + why: 'Bundle entries are malformed or missing required fields.', |
| 71 | + fix: 'Each entry needs: resource (for non-DELETE) and request (for transaction/batch).', |
| 72 | + }, |
| 73 | + 'reference-validation-error': { |
| 74 | + why: 'Reference validation failed for an unspecified reason.', |
| 75 | + fix: 'Check reference format, target existence, and type constraints.', |
| 76 | + }, |
| 77 | + 'reference-circular': { |
| 78 | + why: 'A circular reference chain was detected (A → B → A).', |
| 79 | + fix: 'Break the cycle by removing one of the bidirectional references or using a contained resource.', |
| 80 | + }, |
| 81 | + 'reference-recursive-timeout': { |
| 82 | + why: 'Reference resolution was aborted because the chain is too deep.', |
| 83 | + fix: 'Simplify the reference graph. Deep chains often indicate a modelling issue.', |
| 84 | + }, |
| 85 | + 'reference-target-type-invalid': { |
| 86 | + why: 'The referenced resource type is not allowed for this reference element.', |
| 87 | + fix: 'Change the reference to one of the allowed target types defined in the element.', |
| 88 | + }, |
| 89 | + 'reference-unresolved': { |
| 90 | + why: 'The reference could not be resolved to any known resource.', |
| 91 | + fix: 'Ensure the target resource exists, or use a contained/bundled resource.', |
| 92 | + }, |
| 93 | + 'reference-bundle-missing-type': { |
| 94 | + why: 'Bundle.type determines processing rules (transaction, batch, document, etc.).', |
| 95 | + fix: 'Add a type from: document | message | transaction | batch | searchset | collection | history', |
| 96 | + example: '{ "resourceType": "Bundle", "type": "collection", ... }', |
| 97 | + specUrl: 'https://www.hl7.org/fhir/bundle.html#type', |
| 98 | + patch: { action: 'add', path: 'Bundle.type', value: '"collection"' }, |
| 99 | + }, |
| 100 | + 'reference-bundle-entry-missing-request': { |
| 101 | + why: 'Transaction and batch Bundles require request element for processing instructions.', |
| 102 | + fix: 'Add request with method (GET/POST/PUT/DELETE) and url.', |
| 103 | + example: 'request: { method: "POST", url: "Patient" }', |
| 104 | + patch: { action: 'add', path: '{{fieldPath}}.request', value: '{ "method": "POST", "url": "{{resourceType}}" }' }, |
| 105 | + }, |
| 106 | + 'reference-bundle-duplicate-fullurl': { |
| 107 | + why: 'fullUrl must be unique within a Bundle for unambiguous reference resolution.', |
| 108 | + fix: 'Ensure each entry has a unique fullUrl, or use urn:uuid for temporary IDs.', |
| 109 | + }, |
| 110 | + |
| 111 | + // ------------------------------------------------------------------------- |
| 112 | + // Profile |
| 113 | + // ------------------------------------------------------------------------- |
| 114 | + 'profile-constraint-violation': { |
| 115 | + why: 'Profile constraints define additional rules beyond the base FHIR specification. In document Bundles this can also mean a referenced child resource failed targetProfile matching.', |
| 116 | + fix: 'Review the path and details. For targetProfile failures, fix the referenced resource so it conforms to one of the allowed targetProfiles, then revalidate the Bundle.', |
| 117 | + patch: { action: 'replace', path: '{{fieldPath}}', value: '(satisfy constraint {{key}}: {{message}})' }, |
| 118 | + }, |
| 119 | + 'profile-mustsupport-missing': { |
| 120 | + why: 'MustSupport elements should be populated when data is available.', |
| 121 | + fix: 'Add the element if you have the data. If not available, document why.', |
| 122 | + specUrl: 'https://www.hl7.org/fhir/conformance-rules.html#mustSupport', |
| 123 | + }, |
| 124 | + 'profile-slice-min-cardinality': { |
| 125 | + why: 'The profile requires at least one item matching this slice discriminator. For document Bundles, the missing slice may be caused by an entry that exists but does not conform to the required profile.', |
| 126 | + fix: 'Add or repair the element matching the slice. For Bundle.entry:composition, fix the Composition entry and any child targetProfile errors first.', |
| 127 | + example: 'For Bundle.entry:composition: include a Composition entry that conforms to the document profile.', |
| 128 | + patch: { action: 'add', path: '{{fieldPath}}', value: '(add entry matching slice "{{sliceName}}", min={{min}})' }, |
| 129 | + }, |
| 130 | + 'profile-slice-max-cardinality': { |
| 131 | + why: 'The profile limits how many items can match this slice.', |
| 132 | + fix: 'Remove excess elements or verify discriminator values.', |
| 133 | + }, |
| 134 | + 'profile-slice-closed-unmatched': { |
| 135 | + why: 'Closed slicing rejects elements that don\'t match any defined slice.', |
| 136 | + fix: 'Either match an existing slice discriminator, or request the profile be updated.', |
| 137 | + specUrl: 'https://www.hl7.org/fhir/profiling.html#slicing', |
| 138 | + }, |
| 139 | + 'profile-extension-url-missing': { |
| 140 | + why: 'Every extension must have a URL identifying its definition.', |
| 141 | + fix: 'Add the url property with the extension\'s canonical URL.', |
| 142 | + example: '{ "url": "http://example.org/fhir/StructureDefinition/my-extension", "valueString": "..." }', |
| 143 | + patch: { action: 'add', path: '{{fieldPath}}.url', value: '"http://example.org/fhir/StructureDefinition/..."' }, |
| 144 | + }, |
| 145 | + 'profile-extension-not-in-profile': { |
| 146 | + why: 'This extension is not defined in the declared profile.', |
| 147 | + fix: 'Remove the extension, or add its definition to the profile.', |
| 148 | + }, |
| 149 | + 'profile-extension-no-value': { |
| 150 | + why: 'Extensions must have either a value[x] or nested extensions, not neither.', |
| 151 | + fix: 'Add a value using the appropriate type (valueString, valueCode, etc.).', |
| 152 | + }, |
| 153 | + 'profile-extension-missing': { |
| 154 | + why: 'The profile requires this extension to be present.', |
| 155 | + fix: 'Add the extension with its required URL and value.', |
| 156 | + }, |
| 157 | + 'profile-not-found': { |
| 158 | + why: 'The profile could not be loaded from the package registry.', |
| 159 | + fix: 'Install the package containing this profile, or verify the canonical URL.', |
| 160 | + }, |
| 161 | + 'profile-download-failed': { |
| 162 | + why: 'Network or registry error while downloading the profile.', |
| 163 | + fix: 'Check network connectivity and try again. Verify the profile URL is correct.', |
| 164 | + }, |
| 165 | + 'profile-extension-invalid': { |
| 166 | + why: 'The extension structure is malformed or incomplete.', |
| 167 | + fix: 'Ensure the extension has url and either value[x] or nested extension elements.', |
| 168 | + }, |
| 169 | + 'profile-extension-modifier-mismatch': { |
| 170 | + why: 'Modifier extensions must use modifierExtension, not extension.', |
| 171 | + fix: 'Move this to modifierExtension array, or use a non-modifier extension definition.', |
| 172 | + specUrl: 'https://www.hl7.org/fhir/extensibility.html#modifierExtension', |
| 173 | + }, |
| 174 | + 'profile-extension-value-and-nested': { |
| 175 | + why: 'Extensions cannot have both a value[x] and nested extensions.', |
| 176 | + fix: 'Choose either a direct value OR nested extensions, not both.', |
| 177 | + }, |
| 178 | + 'profile-extension-invalid-value-type': { |
| 179 | + why: 'The extension\'s value type doesn\'t match its definition.', |
| 180 | + fix: 'Use the value type specified in the extension definition (e.g., valueString, valueCode).', |
| 181 | + }, |
| 182 | + 'profile-extension-max-depth': { |
| 183 | + why: 'Nested extensions exceed the validator\'s maximum traversal depth. This usually indicates a deeply recursive or cyclic extension tree.', |
| 184 | + fix: 'Flatten the extension hierarchy or split the data across multiple siblings. The default limit is 5 levels of nesting.', |
| 185 | + }, |
| 186 | + 'profile-extension-min-cardinality': { |
| 187 | + why: 'This extension requires a minimum number of occurrences.', |
| 188 | + fix: 'Add additional instances of the extension to meet minimum cardinality.', |
| 189 | + }, |
| 190 | + 'profile-extension-max-cardinality': { |
| 191 | + why: 'Too many instances of this extension are present.', |
| 192 | + fix: 'Remove excess extension instances to stay within maximum cardinality.', |
| 193 | + }, |
| 194 | + 'profile-slicing-violation': { |
| 195 | + why: 'The element violates slicing rules defined in the profile.', |
| 196 | + fix: 'Check the slice discriminator and ensure elements match defined slices.', |
| 197 | + specUrl: 'https://www.hl7.org/fhir/profiling.html#slicing', |
| 198 | + }, |
| 199 | + 'profile-load-error': { |
| 200 | + why: 'The profile could not be loaded or parsed.', |
| 201 | + fix: 'Verify the package is installed. Check for JSON syntax errors if local.', |
| 202 | + }, |
| 203 | + |
| 204 | +}; |
0 commit comments