fhirsmith 0.14.1 → 0.15.0

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 (74) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +3 -2
  3. package/config-template.json +9 -0
  4. package/library/changelog.js +57 -0
  5. package/library/fhir-openapi-schema.js +441 -0
  6. package/library/html-server.js +9 -3
  7. package/library/npm-audit.js +265 -0
  8. package/library/openapi-doc.js +557 -0
  9. package/library/utilities.js +21 -0
  10. package/package.json +10 -4
  11. package/packages/openapi.js +13 -0
  12. package/packages/openapi.yaml +603 -0
  13. package/packages/packages-template.html +4 -2
  14. package/packages/packages.js +286 -81
  15. package/packages/readme.md +120 -0
  16. package/registry/api.js +117 -41
  17. package/registry/crawler.js +41 -0
  18. package/registry/fhirsmith-releases.js +167 -0
  19. package/registry/model.js +13 -0
  20. package/registry/openapi.js +13 -0
  21. package/registry/openapi.yaml +311 -0
  22. package/registry/readme.md +107 -208
  23. package/registry/registry-template.html +4 -1
  24. package/registry/registry.js +198 -19
  25. package/server.js +19 -5
  26. package/testing/openapi-schemas.config.js +58 -0
  27. package/testing/openapi-schemas.json +1920 -0
  28. package/testing/openapi.js +15 -0
  29. package/testing/openapi.yaml +273 -0
  30. package/testing/readme.md +43 -1
  31. package/testing/search.js +1 -1
  32. package/testing/testing-template.html +2 -0
  33. package/testing/testing.js +24 -0
  34. package/translations/Messages.properties +1 -0
  35. package/tx/README.md +78 -4
  36. package/tx/cm/cm-api.js +25 -10
  37. package/tx/cm/cm-database.js +10 -5
  38. package/tx/cm/cm-package.js +61 -15
  39. package/tx/cs/cs-provider-api.js +22 -7
  40. package/tx/cs/cs-provider-list.js +10 -9
  41. package/tx/cs/cs-rxnorm.js +23 -6
  42. package/tx/html/tx-template.html +2 -0
  43. package/tx/library/canonical-resource.js +50 -1
  44. package/tx/library/codesystem.js +1 -0
  45. package/tx/library/conceptmap.js +1 -0
  46. package/tx/library/resource-ids.js +107 -0
  47. package/tx/library/valueset.js +16 -0
  48. package/tx/library.js +113 -26
  49. package/tx/ocl/cm-ocl.cjs +23 -15
  50. package/tx/ocl/cs-ocl.cjs +9 -10
  51. package/tx/ocl/vs-ocl.cjs +17 -17
  52. package/tx/openapi-operations.js +363 -0
  53. package/tx/openapi-schemas.config.js +118 -0
  54. package/tx/openapi-schemas.json +7903 -0
  55. package/tx/openapi.js +289 -0
  56. package/tx/openapi.yaml +151 -0
  57. package/tx/operation-context.js +15 -0
  58. package/tx/params.js +3 -12
  59. package/tx/provider.js +90 -14
  60. package/tx/tx-html.js +6 -0
  61. package/tx/tx.fhir.org.yml +16 -8
  62. package/tx/tx.js +62 -1
  63. package/tx/vs/vs-api.js +25 -10
  64. package/tx/vs/vs-database.js +14 -9
  65. package/tx/vs/vs-package.js +58 -31
  66. package/tx/vs/vs-vsac.js +20 -5
  67. package/tx/workers/expand.js +35 -16
  68. package/tx/workers/metadata.js +2 -14
  69. package/tx/workers/read.js +3 -18
  70. package/tx/workers/validate.js +65 -19
  71. package/tx/workers/worker.js +29 -8
  72. package/utilities/extract-schema-json.js +167 -0
  73. package/utilities/generate-openapi-schemas.js +49 -0
  74. package/xig/xig.js +2 -4
@@ -0,0 +1,363 @@
1
+ //
2
+ // Copyright 2026, Health Intersections Pty Ltd (http://www.healthintersections.com.au)
3
+ //
4
+ // Licensed under BSD-3: https://opensource.org/license/bsd-3-clause
5
+ //
6
+
7
+ // The terminology operations, as data, for the OpenAPI description (see openapi.js).
8
+ //
9
+ // Each operation is described once here, and openapi.js makes the paths from it: the type
10
+ // level and instance level forms, GET (query parameters) and POST (a Parameters resource, or
11
+ // a form), and the tables of in and out parameters in the description. The parameter lists
12
+ // are what the code reads - tests/tx/openapi.test.js checks them against the workers and
13
+ // TxParameters (params.js) - so add a parameter here when the code learns a new one.
14
+ //
15
+ // An operation with common: true also reads the COMMON parameters (listed once, in the
16
+ // overview).
17
+ //
18
+ // A parameter: { name, type, min, max, doc }. type is a FHIR type: a primitive can be sent
19
+ // in a query (GET, or a form), anything else only in a Parameters resource. max is '1' or
20
+ // '*'. parts, for an out parameter with parts, lists them the same way.
21
+
22
+ const ref = (name) => ({ $ref: `#/components/schemas/${name}` });
23
+
24
+ const p = (name, type, max, doc, extra = {}) => ({ name, type, min: 0, max, doc, ...extra });
25
+
26
+ // Additional resources, and the cache they can be kept in. Every operation that resolves
27
+ // code systems or value sets reads these.
28
+ const RESOURCES = [
29
+ p('tx-resource', 'Resource', '*', 'A CodeSystem, ValueSet or ConceptMap the operation may need (e.g. a value set that the value set being expanded imports), used instead of any the server has with the same url and version'),
30
+ p('cache-id', 'id', '1', 'A cache of tx-resources started with $cache-control (mode=start). Sending it in the `X-Cache-Id` header instead is preferred')
31
+ ];
32
+
33
+ // TxParameters (params.js): read by every operation that works with code systems and value sets
34
+ const VERSIONS = [
35
+ p('system-version', 'canonical', '*', 'The version of a code system to use when the value set (or the request) doesn\'t say: `system|version`'),
36
+ p('check-system-version', 'canonical', '*', 'The version of a code system that must be used: `system|version`. It\'s an error if anything else would be'),
37
+ p('force-system-version', 'canonical', '*', 'The version of a code system to use, whatever the value set (or the request) says: `system|version`'),
38
+ p('default-valueset-version', 'canonical', '*', 'The version of a value set to use when a reference to it doesn\'t say: `url|version`'),
39
+ p('check-valueset-version', 'canonical', '*', 'The version of a value set that must be used: `url|version`'),
40
+ p('force-valueset-version', 'canonical', '*', 'The version of a value set to use, whatever the reference to it says: `url|version`'),
41
+ p('default-to-latest-version', 'boolean', '1', 'When no version is specified, use the latest the server has')
42
+ ];
43
+
44
+ const GENERAL = [
45
+ p('displayLanguage', 'code', '1', 'The language(s) for displays, in the form of an HTTP Accept-Language (which is used if this isn\'t present)'),
46
+ p('useSupplement', 'canonical', '*', 'A code system supplement to use, which must then be used (`url` or `url|version`)'),
47
+ p('profile', 'Parameters', '1', 'A Parameters resource holding more of these parameters (an expansion profile)'),
48
+ p('no-cache', 'boolean', '1', 'Don\'t answer from a cached result'),
49
+ p('diagnostics', 'boolean', '1', 'Add the server\'s working to the response (for debugging; the format can change at any time)')
50
+ ];
51
+
52
+ const COMMON = [...RESOURCES, ...VERSIONS, ...GENERAL];
53
+
54
+ const EXPANSION = [
55
+ p('filter', 'string', '1', 'Text to filter the codes by (matching display and designations; how is up to the code system)'),
56
+ p('count', 'integer', '1', 'Paging: the number of codes to return'),
57
+ p('offset', 'integer', '1', 'Paging: where to start (0 based)'),
58
+ p('limit', 'integer', '1', 'Upper bound on the size of the expansion; the operation fails as too-costly beyond it'),
59
+ p('activeOnly', 'boolean', '1', 'Leave out inactive codes'),
60
+ p('excludeNested', 'boolean', '1', 'Return a flat list, not a hierarchy'),
61
+ p('excludeNotForUI', 'boolean', '1', 'Leave out codes that aren\'t for choosing in a user interface (abstract codes)'),
62
+ p('excludePostCoordinated', 'boolean', '1', 'Leave out post-coordinated codes'),
63
+ p('includeDesignations', 'boolean', '1', 'Include the designations of each code'),
64
+ p('designation', 'string', '*', 'A designation to include: `language`, or a `system|code` use'),
65
+ p('includeDefinition', 'boolean', '1', 'Include the definition of each code'),
66
+ p('property', 'string', '*', 'A property to include for each code'),
67
+ p('sort', 'string', '1', '`code`, `display`, `design` or `prop:{name}`; prefix with - to reverse. Ignored for hierarchical expansions'),
68
+ p('versionsMatch', 'boolean', '1', 'Treat a code as the same code in different versions of its code system')
69
+ ];
70
+
71
+ const VALIDATION = [
72
+ p('abstract', 'boolean', '1', 'Whether abstract codes are valid (default true)'),
73
+ p('activeOnly', 'boolean', '1', 'Inactive codes are not valid'),
74
+ p('lenient-display-validation', 'boolean', '1', 'A wrong display is a warning rather than an error'),
75
+ p('valueset-membership-only', 'boolean', '1', 'Only check that the code is in the value set: not the display, status, and so on')
76
+ ];
77
+
78
+ const VALIDATE_RESULT = [
79
+ p('result', 'boolean', '1', 'Whether the code is valid', { min: 1 }),
80
+ p('message', 'string', '1', 'The errors and warnings, as text'),
81
+ p('display', 'string', '1', 'The display of the code'),
82
+ p('code', 'code', '1', 'The code that was validated'),
83
+ p('system', 'uri', '1', 'Its code system'),
84
+ p('version', 'string', '1', 'The version of the code system'),
85
+ p('codeableConcept', 'CodeableConcept', '1', 'The CodeableConcept that was validated'),
86
+ p('inactive', 'boolean', '1', 'The code is inactive'),
87
+ p('status', 'code', '1', 'The status of the code, when it\'s not active'),
88
+ p('normalized-code', 'code', '1', 'The code as the code system has it, when it was validated case-insensitively'),
89
+ p('issues', 'OperationOutcome', '1', 'The issues, with their locations and tx-issue-type codes'),
90
+ p('x-unknown-system', 'canonical', '*', 'A code system (or version) the server doesn\'t have'),
91
+ p('x-caused-by-unknown-system', 'canonical', '*', 'A code system (or version) the server doesn\'t have, which made the validation impossible')
92
+ ];
93
+
94
+ const OPERATIONS = [
95
+ {
96
+ name: 'expand',
97
+ common: true,
98
+ resource: 'ValueSet',
99
+ levels: ['type', 'instance'],
100
+ summary: 'Expand a value set',
101
+ description: 'Returns the codes in a value set, as ValueSet.expansion. The value set is ' +
102
+ 'named by url (and valueSetVersion), or sent as valueSet; at the instance level it\'s ' +
103
+ 'the value set with that id.\n\nA POST can also send the ValueSet itself as the body, ' +
104
+ 'with any other parameters in the query.',
105
+ postBody: ['Parameters', 'ValueSet'],
106
+ in: [
107
+ p('url', 'uri', '1', 'The value set to expand (type level)'),
108
+ p('valueSetVersion', 'string', '1', 'Its version'),
109
+ p('valueSet', 'ValueSet', '1', 'The value set to expand, sent with the request'),
110
+ ...EXPANSION
111
+ ],
112
+ returns: 'ValueSet',
113
+ returnsDoc: 'The value set, with its expansion'
114
+ },
115
+ {
116
+ name: 'validate-code',
117
+ common: true,
118
+ resource: 'ValueSet',
119
+ levels: ['type', 'instance'],
120
+ summary: 'Is a code in a value set?',
121
+ description: 'Validates a code, Coding or CodeableConcept against a value set: whether it\'s ' +
122
+ 'in the value set, and whether it\'s valid in its code system (display, status, and so on).',
123
+ in: [
124
+ p('url', 'uri', '1', 'The value set (type level)'),
125
+ p('valueSetVersion', 'string', '1', 'Its version'),
126
+ p('valueSet', 'ValueSet', '1', 'The value set, sent with the request'),
127
+ p('code', 'code', '1', 'The code to validate (with system)'),
128
+ p('system', 'uri', '1', 'Its code system'),
129
+ p('systemVersion', 'string', '1', 'The version of the code system'),
130
+ p('display', 'string', '1', 'Its display, to check'),
131
+ p('inferSystem', 'boolean', '1', 'Work out the system from the value set, if code has no system'),
132
+ p('coding', 'Coding', '1', 'The Coding to validate'),
133
+ p('codeableConcept', 'CodeableConcept', '1', 'The CodeableConcept to validate: valid if any of its codings is'),
134
+ ...VALIDATION
135
+ ],
136
+ out: VALIDATE_RESULT
137
+ },
138
+ {
139
+ name: 'validate-code',
140
+ common: true,
141
+ resource: 'CodeSystem',
142
+ levels: ['type', 'instance'],
143
+ summary: 'Is a code valid in a code system?',
144
+ description: 'Validates a code, Coding or CodeableConcept against a code system.',
145
+ in: [
146
+ p('url', 'uri', '1', 'The code system (type level; system is accepted too)'),
147
+ p('version', 'string', '1', 'Its version'),
148
+ p('codeSystem', 'CodeSystem', '1', 'The code system, sent with the request'),
149
+ p('code', 'code', '1', 'The code to validate'),
150
+ p('system', 'uri', '1', 'The code system, if url isn\'t given'),
151
+ p('display', 'string', '1', 'Its display, to check'),
152
+ p('coding', 'Coding', '1', 'The Coding to validate'),
153
+ p('codeableConcept', 'CodeableConcept', '1', 'The CodeableConcept to validate'),
154
+ ...VALIDATION.filter(x => x.name !== 'valueset-membership-only')
155
+ ],
156
+ out: VALIDATE_RESULT
157
+ },
158
+ {
159
+ name: 'batch-validate-code',
160
+ resource: 'ValueSet',
161
+ levels: ['type'],
162
+ methods: ['post'],
163
+ summary: 'Validate many codes against value sets',
164
+ description: 'A batch of $validate-code requests: each `validation` is a Parameters resource ' +
165
+ 'with the parameters of one ValueSet $validate-code. url, valueSet, tx-resource and ' +
166
+ 'lenient-display-validation at the top level apply to every validation that doesn\'t ' +
167
+ 'have its own. Each result is a `validation` in the response, in the same order: the ' +
168
+ 'Parameters $validate-code returns, or an OperationOutcome.',
169
+ postBody: ['Parameters'],
170
+ in: [
171
+ p('validation', 'Parameters', '*', 'The parameters of one $validate-code', { min: 1 }),
172
+ p('url', 'uri', '1', 'The value set, for every validation'),
173
+ p('valueSet', 'ValueSet', '1', 'The value set, for every validation'),
174
+ p('lenient-display-validation', 'boolean', '1', 'For every validation'),
175
+ p('tx-resource', 'Resource', '*', 'Resources for every validation')
176
+ ],
177
+ out: [p('validation', 'Parameters', '*', 'The result of each validation (or an OperationOutcome)')]
178
+ },
179
+ {
180
+ name: 'batch-validate-code',
181
+ resource: 'CodeSystem',
182
+ levels: ['type'],
183
+ methods: ['post'],
184
+ summary: 'Validate many codes against code systems',
185
+ description: 'A batch of CodeSystem $validate-code requests: each `validation` is a ' +
186
+ 'Parameters resource with the parameters of one. system, codeSystem, tx-resource and ' +
187
+ 'lenient-display-validation at the top level apply to every validation that doesn\'t ' +
188
+ 'have its own.',
189
+ postBody: ['Parameters'],
190
+ in: [
191
+ p('validation', 'Parameters', '*', 'The parameters of one $validate-code', { min: 1 }),
192
+ p('system', 'uri', '1', 'The code system, for every validation'),
193
+ p('codeSystem', 'CodeSystem', '1', 'The code system, for every validation'),
194
+ p('lenient-display-validation', 'boolean', '1', 'For every validation'),
195
+ p('tx-resource', 'Resource', '*', 'Resources for every validation')
196
+ ],
197
+ out: [p('validation', 'Parameters', '*', 'The result of each validation (or an OperationOutcome)')]
198
+ },
199
+ {
200
+ name: 'lookup',
201
+ common: true,
202
+ resource: 'CodeSystem',
203
+ levels: ['type', 'instance'],
204
+ summary: 'Look up a code',
205
+ description: 'Returns the details of a code: its display, definition, designations and properties.',
206
+ in: [
207
+ p('code', 'code', '1', 'The code (with system)'),
208
+ p('system', 'uri', '1', 'Its code system (type level)'),
209
+ p('version', 'string', '1', 'The version of the code system'),
210
+ p('coding', 'Coding', '1', 'The code, as a Coding'),
211
+ p('property', 'code', '*', 'A property to return (by default, all of them)'),
212
+ ],
213
+ out: [
214
+ p('name', 'string', '1', 'The name of the code system', { min: 1 }),
215
+ p('system', 'uri', '1', 'The code system'),
216
+ p('version', 'string', '1', 'Its version'),
217
+ p('code', 'code', '1', 'The code'),
218
+ p('display', 'string', '1', 'Its display', { min: 1 }),
219
+ p('definition', 'string', '1', 'Its definition'),
220
+ p('abstract', 'boolean', '1', 'Whether it\'s abstract (not for use)'),
221
+ p('designation', '(parts)', '*', 'A designation', {
222
+ parts: [
223
+ p('language', 'code', '1', ''), p('use', 'Coding', '1', ''), p('value', 'string', '1', ''),
224
+ p('source', 'Coding', '1', 'Where the designation comes from (e.g. a supplement)'),
225
+ p('status', 'code', '1', '')
226
+ ]
227
+ }),
228
+ p('property', '(parts)', '*', 'A property', {
229
+ parts: [p('code', 'code', '1', ''), p('value', 'any', '1', ''), p('description', 'string', '1', '')]
230
+ }),
231
+ p('used-supplement', 'canonical', '*', 'A supplement that was used')
232
+ ]
233
+ },
234
+ {
235
+ name: 'subsumes',
236
+ common: true,
237
+ resource: 'CodeSystem',
238
+ levels: ['type', 'instance'],
239
+ summary: 'Does one code subsume another?',
240
+ description: 'Tests the relationship between two codes in a code system.',
241
+ in: [
242
+ p('codeA', 'code', '1', 'The first code'),
243
+ p('codeB', 'code', '1', 'The second code'),
244
+ p('system', 'uri', '1', 'Their code system (type level)'),
245
+ p('version', 'string', '1', 'Its version'),
246
+ p('codingA', 'Coding', '1', 'The first code, as a Coding'),
247
+ p('codingB', 'Coding', '1', 'The second code, as a Coding'),
248
+ ],
249
+ out: [
250
+ p('outcome', 'code', '1', '`equivalent`, `subsumes`, `subsumed-by` or `not-subsumed`', { min: 1 })
251
+ ]
252
+ },
253
+ {
254
+ name: 'translate',
255
+ common: true,
256
+ resource: 'ConceptMap',
257
+ levels: ['type', 'instance'],
258
+ summary: 'Translate a code',
259
+ description: 'Translates a code using a concept map: the one named by url (or the instance), ' +
260
+ 'or the ones the server has that map between the source and target. The R5 names are ' +
261
+ 'used here; the R4 names (code, coding, codeableConcept, system, version, source, target, ' +
262
+ 'targetsystem, reverse) are accepted too.',
263
+ in: [
264
+ p('url', 'uri', '1', 'The concept map (type level)'),
265
+ p('conceptMapVersion', 'string', '1', 'Its version'),
266
+ p('sourceCode', 'code', '1', 'The code to translate (with sourceSystem)'),
267
+ p('sourceSystem', 'uri', '1', 'Its code system'),
268
+ p('sourceVersion', 'string', '1', 'The version of the code system'),
269
+ p('sourceCoding', 'Coding', '1', 'The code to translate, as a Coding'),
270
+ p('sourceCodeableConcept', 'CodeableConcept', '1', 'The code to translate, as a CodeableConcept (its first coding)'),
271
+ p('targetCode', 'code', '1', 'A target code to translate back from (with targetSystem)'),
272
+ p('targetCoding', 'Coding', '1', 'A target code to translate back from, as a Coding'),
273
+ p('targetCodeableConcept', 'CodeableConcept', '1', 'A target code to translate back from, as a CodeableConcept'),
274
+ p('targetVersion', 'string', '1', 'The version of the target code system'),
275
+ p('sourceScope', 'uri', '1', 'The value set the source is in'),
276
+ p('targetScope', 'uri', '1', 'The value set to translate into'),
277
+ p('targetSystem', 'uri', '1', 'The code system to translate into'),
278
+ ],
279
+ out: [
280
+ p('result', 'boolean', '1', 'Whether there\'s a translation', { min: 1 }),
281
+ p('message', 'string', '1', 'More about the result'),
282
+ p('match', '(parts)', '*', 'A translation', {
283
+ parts: [
284
+ p('relationship', 'code', '1', 'How the target relates to the source'),
285
+ p('concept', 'Coding', '1', 'The target'),
286
+ p('product', '(parts)', '*', 'Another element of the product (element, concept)'),
287
+ p('originMap', 'canonical', '1', 'The concept map'),
288
+ p('sourceConcept', 'Coding', '1', 'What was translated (for a translation in reverse)')
289
+ ]
290
+ }),
291
+ p('used-conceptmap', 'canonical', '*', 'A concept map that was used')
292
+ ]
293
+ },
294
+ {
295
+ name: 'compare',
296
+ common: true,
297
+ resource: 'ValueSet',
298
+ levels: ['type', 'instance'],
299
+ summary: 'Compare two value sets',
300
+ description: 'Compares two value sets: by their definitions where that\'s enough, and ' +
301
+ 'otherwise by their expansions. At the instance level, the instance is `this`.',
302
+ in: [
303
+ p('thisUrl', 'uri', '1', 'The first value set'),
304
+ p('thisValueSet', 'ValueSet', '1', 'The first value set, sent with the request'),
305
+ p('otherUrl', 'uri', '1', 'The second value set'),
306
+ p('otherValueSet', 'ValueSet', '1', 'The second value set, sent with the request'),
307
+ p('valueSetVersion', 'string', '1', 'The version of a value set named by url'),
308
+ ],
309
+ out: [
310
+ p('result', 'code', '1', '`same`, `superset`, `subset`, `overlapping`, `disjoint`, `empty` or `indeterminate`', { min: 1 }),
311
+ p('message', 'string', '1', 'The result, as text'),
312
+ p('missing-codes', 'string', '1', 'diagnostics: the codes in the first value set and not the second (comma separated)'),
313
+ p('extra-codes', 'string', '1', 'diagnostics: the codes in the second value set and not the first (comma separated)'),
314
+ p('common-codes', 'string', '1', 'diagnostics: the codes in both (comma separated)'),
315
+ p('performed-expansion', 'boolean', '1', 'diagnostics: whether the value sets had to be expanded')
316
+ ]
317
+ },
318
+ {
319
+ name: 'closure',
320
+ resource: null,
321
+ levels: ['system'],
322
+ methods: ['post'],
323
+ summary: 'Maintain a closure table',
324
+ description: 'Adds concepts to a named closure table, and returns the new relationships, as ' +
325
+ 'a ConceptMap. Only POST: the operation changes the table. Not every server keeps closure ' +
326
+ 'tables (501 if not).',
327
+ in: [
328
+ p('name', 'string', '1', 'The closure table', { min: 1 }),
329
+ p('concept', 'Coding', '*', 'A concept to add'),
330
+ p('version', 'string', '1', 'Return the changes since this version of the table, instead of adding concepts'),
331
+ p('reset', 'boolean', '1', 'Start the table again')
332
+ ],
333
+ returns: 'ConceptMap',
334
+ returnsDoc: 'The new relationships'
335
+ },
336
+ {
337
+ name: 'cache-control',
338
+ resource: null,
339
+ levels: ['system'],
340
+ summary: 'Manage a cache of resources',
341
+ description: 'A client that sends the same tx-resources with many requests can keep them in ' +
342
+ 'a cache on the server instead. `mode=start` creates a cache (with the tx-resources sent ' +
343
+ 'with it) and returns its id; later requests send the id in the `X-Cache-Id` header. ' +
344
+ '`mode=check` reports whether the cache is still there (and keeps it alive); `mode=end` ' +
345
+ 'releases it. Caches expire when they aren\'t used.',
346
+ in: [
347
+ p('mode', 'code', '1', '`start`, `check` or `end` (in the query, even for a POST)', { min: 1, inQuery: true }),
348
+ p('sealed', 'boolean', '1', 'start: whether the cache holds only what\'s sent now (default false: it grows with the tx-resources later requests send)'),
349
+ p('tx-resource', 'Resource', '*', 'start: resources to put in the cache')
350
+ ],
351
+ out: [
352
+ p('cache-id', 'id', '1', 'start: the new cache\'s id; check: the cache checked'),
353
+ p('sealed', 'boolean', '1', 'start, check: whether it\'s sealed'),
354
+ p('valid', 'boolean', '1', 'check: whether the cache is still there'),
355
+ p('outcome', 'OperationOutcome', '1', 'check: why it isn\'t (when valid is false)'),
356
+ p('resource-count', 'unsignedInt', '1', 'check: how many resources it holds'),
357
+ p('idle', 'unsignedInt', '1', 'check: how long it has been unused (seconds)'),
358
+ p('timeout', 'unsignedInt', '1', 'check: how long it can be unused before it expires (seconds)')
359
+ ]
360
+ }
361
+ ];
362
+
363
+ module.exports = { OPERATIONS, COMMON, RESOURCES, VERSIONS, GENERAL, EXPANSION, VALIDATION, ref };
@@ -0,0 +1,118 @@
1
+ // What utilities/generate-openapi-schemas.js generates for the terminology server's OpenAPI
2
+ // description (into openapi-schemas.json, which the loader merges into the components of the
3
+ // description - see openapi.js). Regenerate after changing this:
4
+ //
5
+ // node utilities/generate-openapi-schemas.js tx
6
+ //
7
+ // tests/tx/openapi.test.js fails if the generated file is out of date, and validates real
8
+ // responses against these schemas.
9
+ //
10
+ // The schemas are R5, and they are documentation: they describe what this server handles,
11
+ // and what it returns. The server doesn't reject content outside them (an extension with a
12
+ // Quantity value, say) - but it isn't designed to do anything with it either.
13
+
14
+ const ref = (name) => ({ $ref: `#/components/schemas/${name}` });
15
+
16
+ // The resources the server works with: they're what a Bundle, or a Parameters, can hold
17
+ const TX_RESOURCES = ['CodeSystem', 'ValueSet', 'ConceptMap', 'OperationOutcome'];
18
+
19
+ // The types of an extension's value, and of a parameter's value: the primitive types
20
+ // (except base64Binary, and xhtml, which isn't a choice anyway), Coding and CodeableConcept
21
+ const VALUE_TYPES = [
22
+ 'boolean', 'canonical', 'code', 'date', 'dateTime', 'decimal', 'id', 'instant', 'integer',
23
+ 'integer64', 'markdown', 'oid', 'positiveInt', 'string', 'time', 'unsignedInt', 'uri', 'url',
24
+ 'uuid', 'Coding', 'CodeableConcept'
25
+ ];
26
+
27
+ const TX_ISSUE_TYPE = 'http://hl7.org/fhir/tools/CodeSystem/tx-issue-type';
28
+
29
+ function searchBundle(type) {
30
+ return {
31
+ description: `A searchset Bundle of ${type}s`,
32
+ allOf: [
33
+ ref('Bundle'),
34
+ {
35
+ type: 'object',
36
+ properties: {
37
+ type: { const: 'searchset' },
38
+ entry: { type: 'array', items: { type: 'object', properties: { resource: ref(type) } } }
39
+ }
40
+ }
41
+ ]
42
+ };
43
+ }
44
+
45
+ module.exports = {
46
+ package: 'hl7.fhir.r5.core#5.0.0',
47
+ roots: [...TX_RESOURCES, 'Parameters', 'Bundle', 'CapabilityStatement', 'TerminologyCapabilities'],
48
+
49
+ // Contained resources: only value sets, in a value set (and they can't contain anything
50
+ // themselves - see the ValueSet overlay)
51
+ prohibit: [
52
+ 'CodeSystem.contained', 'ConceptMap.contained', 'OperationOutcome.contained',
53
+ 'CapabilityStatement.contained', 'TerminologyCapabilities.contained'
54
+ ],
55
+ resources: {
56
+ 'ValueSet.contained': ['ValueSet'],
57
+ // Bundles never hold Bundles. A Parameters holds a Parameters only as a `validation`
58
+ // in $batch-validate-code, and as a `profile`
59
+ 'Bundle.entry.resource': TX_RESOURCES,
60
+ 'Bundle.entry.response.outcome': ['OperationOutcome'],
61
+ 'Bundle.issues': ['OperationOutcome'],
62
+ 'Parameters.parameter.resource': [...TX_RESOURCES, 'Parameters']
63
+ },
64
+ generateExtension: true,
65
+ choiceTypes: {
66
+ 'Extension.value[x]': VALUE_TYPES,
67
+ 'Parameters.parameter.value[x]': VALUE_TYPES
68
+ },
69
+
70
+ overlay: {
71
+ ValueSet: {
72
+ properties: {
73
+ contained: {
74
+ description: 'Contained value sets, which the value set includes or excludes by reference (#id). ' +
75
+ 'Only value sets can be contained, and they can\'t contain resources themselves'
76
+ }
77
+ }
78
+ },
79
+
80
+ Parameters: {
81
+ description: 'Operation parameters, in or out. Each operation lists the parameters it uses. ' +
82
+ 'A parameter\'s value is a primitive, a Coding or a CodeableConcept; its resource is a CodeSystem, ' +
83
+ 'ValueSet, ConceptMap or OperationOutcome, or a Parameters - which only a `validation` in ' +
84
+ '$batch-validate-code (and its result), and a `profile` (an expansion profile), hold.'
85
+ },
86
+
87
+ // Every issue says what it's about in details.text, and - unless it's just information,
88
+ // like a server banner - classifies it with a tx-issue-type code in details.coding.
89
+ // diagnostics is server-specific detail that clients shouldn't depend on.
90
+ OperationOutcome_Issue: {
91
+ required: ['details'],
92
+ properties: {
93
+ details: {
94
+ $replace: true,
95
+ description: 'What the issue is: details.text, and (except for information) a tx-issue-type coding (' + TX_ISSUE_TYPE + ')',
96
+ allOf: [ref('CodeableConcept'), { required: ['text'] }]
97
+ }
98
+ },
99
+ if: { properties: { severity: { const: 'information' } } },
100
+ else: {
101
+ properties: {
102
+ details: {
103
+ required: ['coding'],
104
+ properties: {
105
+ coding: {
106
+ contains: { type: 'object', properties: { system: { const: TX_ISSUE_TYPE } }, required: ['system', 'code'] }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ },
113
+
114
+ CodeSystemSearchBundle: searchBundle('CodeSystem'),
115
+ ValueSetSearchBundle: searchBundle('ValueSet'),
116
+ ConceptMapSearchBundle: searchBundle('ConceptMap')
117
+ }
118
+ };