fhirsmith 0.13.4 → 0.14.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 (46) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/README.md +16 -3
  3. package/config-template.json +70 -1
  4. package/library/cgroup-memory.js +113 -0
  5. package/library/folder-setup.js +8 -1
  6. package/nginx.md +391 -0
  7. package/package.json +3 -2
  8. package/publisher/git-remote.js +141 -0
  9. package/publisher/github-release.js +195 -0
  10. package/publisher/publisher.js +146 -14
  11. package/server.js +51 -14
  12. package/stats.js +19 -13
  13. package/testing/readme.md +112 -0
  14. package/testing/render.js +482 -0
  15. package/testing/search.js +378 -0
  16. package/testing/store.js +266 -0
  17. package/testing/testing-template.html +126 -0
  18. package/testing/testing.js +486 -0
  19. package/translations/Messages.properties +32 -0
  20. package/tx/closure/closure-store.js +396 -0
  21. package/tx/cs/cs-api.js +6 -1
  22. package/tx/cs/cs-rxnorm.js +35 -8
  23. package/tx/cs/cs-snomed.js +22 -3
  24. package/tx/html/codesystem-operations.liquid +177 -0
  25. package/tx/html/ecl-panel.liquid +93 -0
  26. package/tx/html/home-metrics.liquid +39 -76
  27. package/tx/html/tx-template.html +1 -0
  28. package/tx/library/conceptmap.js +22 -6
  29. package/tx/library/designations.js +12 -3
  30. package/tx/library/operation-outcome.js +3 -1
  31. package/tx/library/renderer.js +42 -5
  32. package/tx/operation-context.js +80 -17
  33. package/tx/provider.js +85 -0
  34. package/tx/sct/expressions.js +128 -44
  35. package/tx/tx-html.js +426 -44
  36. package/tx/tx.js +117 -9
  37. package/tx/workers/cache-control.js +2 -2
  38. package/tx/workers/closure.js +483 -13
  39. package/tx/workers/metadata.js +8 -3
  40. package/tx/workers/read.js +18 -3
  41. package/tx/workers/subsumes.js +18 -2
  42. package/tx/workers/translate.js +167 -20
  43. package/tx/workers/validate.js +61 -182
  44. package/tx/workers/worker.js +9 -0
  45. package/tx/xversion/xv-conceptmap.js +17 -8
  46. package/utilities/submit-test-report.js +150 -0
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+ //
3
+ // Copyright 2026, Health Intersections Pty Ltd (http://www.healthintersections.com.au)
4
+ //
5
+ // Licensed under BSD-3: https://opensource.org/license/bsd-3-clause
6
+ //
7
+
8
+ /**
9
+ * Submit the tx test report (test-cases-report.json, written by the tx test run) to a
10
+ * FHIRsmith /testing server.
11
+ *
12
+ * node utilities/submit-test-report.js [-server url] [-file path] [-token token] [-header name]
13
+ *
14
+ * -server the /testing base; default https://testing.fhir.org/testing
15
+ * -file default test-cases-report.json in the FHIRsmith root
16
+ * -token if the server requires one; or set FHIRSMITH_TESTING_TOKEN
17
+ * -header the header the token goes in; default Authorization (sent as "Bearer <token>")
18
+ *
19
+ * Exits 0 when the server accepted the report, 1 otherwise.
20
+ */
21
+
22
+ const fs = require('fs');
23
+ const path = require('path');
24
+
25
+ const DEFAULT_SERVER = 'https://testing.fhir.org/testing';
26
+ const DEFAULT_FILE = path.join(__dirname, '..', 'test-cases-report.json');
27
+
28
+ function usage(msg) {
29
+ if (msg) {
30
+ console.error(msg);
31
+ }
32
+ console.error('Usage: node utilities/submit-test-report.js [-server url] [-file path] [-token token] [-header name]');
33
+ process.exit(1);
34
+ }
35
+
36
+ function parseArgs(argv) {
37
+ const opts = {
38
+ server: DEFAULT_SERVER,
39
+ file: DEFAULT_FILE,
40
+ token: process.env.FHIRSMITH_TESTING_TOKEN || null,
41
+ header: 'Authorization'
42
+ };
43
+ for (let i = 0; i < argv.length; i++) {
44
+ const a = argv[i].replace(/^--?/, '');
45
+ if (a === 'help' || a === 'h') {
46
+ usage();
47
+ }
48
+ if (!['server', 'file', 'token', 'header'].includes(a)) {
49
+ usage(`Unknown parameter: ${argv[i]}`);
50
+ }
51
+ if (i + 1 >= argv.length) {
52
+ usage(`Missing value for ${argv[i]}`);
53
+ }
54
+ opts[a] = argv[++i];
55
+ }
56
+ return opts;
57
+ }
58
+
59
+ /** The TestReport endpoint for a server base, whether or not it was given with /TestReport. */
60
+ function endpoint(server) {
61
+ const base = server.replace(/\/+$/, '');
62
+ return /\/TestReport$/.test(base) ? base : base + '/TestReport';
63
+ }
64
+
65
+ /** Warn if the report doesn't describe the version being released. */
66
+ function checkVersion(report) {
67
+ const pkg = require('../package.json');
68
+ const fhirsmith = (report.participant || []).find(p => p && p.uri === 'https://github.com/HealthIntersections/FHIRsmith');
69
+ const reported = fhirsmith && typeof fhirsmith.version === 'string' ? fhirsmith.version : null;
70
+ if (reported && reported !== pkg.version) {
71
+ console.warn(`Warning: the report is from FHIRsmith v${reported}, but package.json is v${pkg.version}`);
72
+ } else if (reported && /snapshot/i.test(reported)) {
73
+ console.warn(`Warning: the report is from a snapshot (v${reported}), not a release`);
74
+ }
75
+ }
76
+
77
+ function describeOutcome(text) {
78
+ try {
79
+ const oo = JSON.parse(text);
80
+ if (oo.resourceType === 'OperationOutcome' && Array.isArray(oo.issue)) {
81
+ return oo.issue.map(i => ` ${i.severity}: ${(i.details && i.details.text) || i.diagnostics || i.code}`).join('\n');
82
+ }
83
+ } catch {
84
+ // not JSON - fall through to the raw text
85
+ }
86
+ return ' ' + text.substring(0, 1000);
87
+ }
88
+
89
+ async function main() {
90
+ const opts = parseArgs(process.argv.slice(2));
91
+
92
+ if (!fs.existsSync(opts.file)) {
93
+ console.error(`No report at ${opts.file} - run the tx tests first (npx jest tests/tx/test-cases.test.js)`);
94
+ process.exit(1);
95
+ }
96
+ const body = fs.readFileSync(opts.file, 'utf8');
97
+ let report;
98
+ try {
99
+ report = JSON.parse(body);
100
+ } catch (e) {
101
+ console.error(`${opts.file} is not valid JSON: ${e.message}`);
102
+ process.exit(1);
103
+ }
104
+ if (report.resourceType !== 'TestReport') {
105
+ console.error(`${opts.file} is not a TestReport`);
106
+ process.exit(1);
107
+ }
108
+ checkVersion(report);
109
+
110
+ const url = endpoint(opts.server);
111
+ const headers = {
112
+ 'Content-Type': 'application/fhir+json',
113
+ 'Accept': 'application/fhir+json',
114
+ 'Prefer': 'return=minimal'
115
+ };
116
+ if (opts.token) {
117
+ headers[opts.header] = opts.header.toLowerCase() === 'authorization' ? `Bearer ${opts.token}` : opts.token;
118
+ }
119
+
120
+ console.log(`Submitting ${path.basename(opts.file)} (${report.result}, ${Array.isArray(report.test) ? report.test.length : 0} tests) to ${url}`);
121
+ let res;
122
+ try {
123
+ res = await fetch(url, { method: 'POST', headers, body });
124
+ } catch (e) {
125
+ console.error(`Could not reach ${url}: ${e.cause ? e.cause.message : e.message}`);
126
+ process.exit(1);
127
+ }
128
+ const text = await res.text();
129
+ if (res.status !== 201) {
130
+ console.error(`The server refused the report: HTTP ${res.status}`);
131
+ if (text) {
132
+ console.error(describeOutcome(text));
133
+ }
134
+ if (res.status === 401 && !opts.token) {
135
+ console.error('The server requires a token: use -token, or set FHIRSMITH_TESTING_TOKEN');
136
+ }
137
+ process.exit(1);
138
+ }
139
+ const location = res.headers.get('location');
140
+ console.log(`Accepted: ${location || '(no Location returned)'}`);
141
+ }
142
+
143
+ if (require.main === module) {
144
+ main().catch(e => {
145
+ console.error(e.stack || e.message);
146
+ process.exit(1);
147
+ });
148
+ }
149
+
150
+ module.exports = { parseArgs, endpoint };