fhirsmith 0.5.6 → 0.6.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.
- package/CHANGELOG.md +18 -0
- package/library/html-server.js +2 -1
- package/library/package-manager.js +37 -32
- package/library/utilities.js +10 -1
- package/package.json +1 -1
- package/packages/package-crawler.js +103 -46
- package/packages/packages.js +14 -7
- package/publisher/publisher.js +15 -3
- package/registry/api.js +173 -191
- package/registry/crawler.js +72 -58
- package/registry/model.js +14 -8
- package/registry/registry.js +2 -0
- package/root-template.html +1 -0
- package/server.js +109 -45
- package/tx/cs/cs-api.js +18 -1
- package/tx/cs/cs-base.js +1 -0
- package/tx/cs/cs-rxnorm.js +9 -2
- package/tx/cs/cs-snomed.js +17 -2
- package/tx/html/codesystem-operations.liquid +17 -24
- package/tx/html/valueset-operations.liquid +46 -52
- package/tx/library/codesystem.js +6 -1
- package/tx/library/renderer.js +81 -7
- package/tx/library.js +18 -3
- package/tx/provider.js +4 -2
- package/tx/sct/expressions.js +20 -9
- package/tx/tx-html.js +143 -50
- package/tx/tx.js +2 -2
- package/tx/workers/expand.js +61 -9
- package/tx/workers/search.js +5 -2
- package/tx/xversion/xv-terminologyCapabilities.js +1 -1
package/registry/api.js
CHANGED
|
@@ -23,57 +23,51 @@ class RegistryAPI {
|
|
|
23
23
|
const rows = [];
|
|
24
24
|
const data = this.crawler.getData();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
data.registries.forEach(registry => {
|
|
30
|
-
if (registryCode && registry.code !== registryCode) return;
|
|
31
|
-
|
|
32
|
-
registry.servers.forEach(server => {
|
|
33
|
-
if (serverCode && server.code !== serverCode) return;
|
|
26
|
+
data.registries.forEach(registry => {
|
|
27
|
+
if (registryCode && registry.code !== registryCode) return;
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
registry.servers.forEach(server => {
|
|
30
|
+
if (serverCode && server.code !== serverCode) return;
|
|
31
|
+
|
|
32
|
+
// Check if server is authoritative for this code system
|
|
33
|
+
const isAuth = codeSystem ? ServerRegistryUtilities.hasMatchingCodeSystem(
|
|
34
|
+
codeSystem,
|
|
35
|
+
server.authCSList,
|
|
36
|
+
true // support wildcards
|
|
37
|
+
) : false;
|
|
38
|
+
|
|
39
|
+
server.versions.forEach(versionInfo => {
|
|
40
|
+
if (version && !ServerRegistryUtilities.versionMatches(version, versionInfo.version)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
// Always skip servers with errors - they can't serve requests
|
|
45
|
+
if (versionInfo.error) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
49
|
+
// Include if:
|
|
50
|
+
// 1. Authoritative for the requested code system
|
|
51
|
+
// 2. No filter specified
|
|
52
|
+
// 3. Has the code system in its list
|
|
53
|
+
if (isAuth ||
|
|
54
|
+
!codeSystem ||
|
|
55
|
+
(codeSystem && ServerRegistryUtilities.hasMatchingCodeSystem(
|
|
56
|
+
codeSystem,
|
|
57
|
+
versionInfo.codeSystems,
|
|
58
|
+
false // no wildcards for actual content
|
|
59
|
+
))) {
|
|
60
|
+
const row = ServerRegistryUtilities.createRow(
|
|
61
|
+
registry,
|
|
62
|
+
server,
|
|
63
|
+
versionInfo,
|
|
64
|
+
isAuth
|
|
65
|
+
);
|
|
66
|
+
rows.push(row);
|
|
67
|
+
}
|
|
72
68
|
});
|
|
73
69
|
});
|
|
74
|
-
}
|
|
75
|
-
data.unlock();
|
|
76
|
-
}
|
|
70
|
+
});
|
|
77
71
|
|
|
78
72
|
return this._sortAndRankRows(rows);
|
|
79
73
|
}
|
|
@@ -93,70 +87,65 @@ class RegistryAPI {
|
|
|
93
87
|
const rows = [];
|
|
94
88
|
const data = this.crawler.getData();
|
|
95
89
|
|
|
96
|
-
data.
|
|
97
|
-
|
|
98
|
-
data.registries.forEach(registry => {
|
|
99
|
-
if (registryCode && registry.code !== registryCode) return;
|
|
100
|
-
|
|
101
|
-
registry.servers.forEach(server => {
|
|
102
|
-
if (serverCode && server.code !== serverCode) return;
|
|
90
|
+
data.registries.forEach(registry => {
|
|
91
|
+
if (registryCode && registry.code !== registryCode) return;
|
|
103
92
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
93
|
+
registry.servers.forEach(server => {
|
|
94
|
+
if (serverCode && server.code !== serverCode) return;
|
|
95
|
+
|
|
96
|
+
// Check if server is authoritative for this value set
|
|
97
|
+
const isAuth = valueSet ? ServerRegistryUtilities.hasMatchingValueSet(
|
|
98
|
+
valueSet,
|
|
99
|
+
server.authVSList,
|
|
100
|
+
true // support wildcards
|
|
101
|
+
) : false;
|
|
102
|
+
|
|
103
|
+
server.versions.forEach(versionInfo => {
|
|
104
|
+
if (version && !ServerRegistryUtilities.versionMatches(version, versionInfo.version)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
115
107
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
// Always skip servers with errors - they can't serve requests
|
|
109
|
+
if (versionInfo.error) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
120
112
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
// Include if:
|
|
114
|
+
// 1. No filter specified
|
|
115
|
+
// 2. Authoritative for the value set (even via wildcard)
|
|
116
|
+
// 3. Has the value set in its list
|
|
117
|
+
let includeRow = false;
|
|
126
118
|
|
|
127
|
-
|
|
128
|
-
|
|
119
|
+
if (!valueSet) {
|
|
120
|
+
// No filter, include all working servers
|
|
121
|
+
includeRow = true;
|
|
122
|
+
} else {
|
|
123
|
+
// Check if actually has the value set
|
|
124
|
+
const hasValueSet = ServerRegistryUtilities.hasMatchingValueSet(
|
|
125
|
+
valueSet,
|
|
126
|
+
versionInfo.valueSets,
|
|
127
|
+
false // no wildcards for actual content
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Include if authoritative OR has the value set
|
|
131
|
+
// This matches the Pascal logic: if auth or hasMatchingValueSet
|
|
132
|
+
if (isAuth || hasValueSet) {
|
|
129
133
|
includeRow = true;
|
|
130
|
-
} else {
|
|
131
|
-
// Check if actually has the value set
|
|
132
|
-
const hasValueSet = ServerRegistryUtilities.hasMatchingValueSet(
|
|
133
|
-
valueSet,
|
|
134
|
-
versionInfo.valueSets,
|
|
135
|
-
false // no wildcards for actual content
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
// Include if authoritative OR has the value set
|
|
139
|
-
// This matches the Pascal logic: if auth or hasMatchingValueSet
|
|
140
|
-
if (isAuth || hasValueSet) {
|
|
141
|
-
includeRow = true;
|
|
142
|
-
}
|
|
143
134
|
}
|
|
135
|
+
}
|
|
144
136
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
});
|
|
137
|
+
if (includeRow) {
|
|
138
|
+
const row = ServerRegistryUtilities.createRow(
|
|
139
|
+
registry,
|
|
140
|
+
server,
|
|
141
|
+
versionInfo,
|
|
142
|
+
isAuth
|
|
143
|
+
);
|
|
144
|
+
rows.push(row);
|
|
145
|
+
}
|
|
155
146
|
});
|
|
156
147
|
});
|
|
157
|
-
}
|
|
158
|
-
data.unlock();
|
|
159
|
-
}
|
|
148
|
+
});
|
|
160
149
|
|
|
161
150
|
return this._sortAndRankRows(rows);
|
|
162
151
|
}
|
|
@@ -254,7 +243,7 @@ class RegistryAPI {
|
|
|
254
243
|
workingVersions++;
|
|
255
244
|
}
|
|
256
245
|
|
|
257
|
-
version.codeSystems.forEach(cs => totalCodeSystems.add(cs));
|
|
246
|
+
version.codeSystems.forEach(cs => totalCodeSystems.add(cs.uri+(cs.version ? '|'+cs.version : '')));
|
|
258
247
|
version.valueSets.forEach(vs => totalValueSets.add(vs));
|
|
259
248
|
});
|
|
260
249
|
});
|
|
@@ -415,13 +404,49 @@ class RegistryAPI {
|
|
|
415
404
|
baseCodeSystem = codeSystem.substring(0, codeSystem.indexOf('|'));
|
|
416
405
|
}
|
|
417
406
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
407
|
+
data.registries.forEach(registry => {
|
|
408
|
+
registry.servers.forEach(server => {
|
|
409
|
+
let added = false;
|
|
410
|
+
|
|
411
|
+
// Check if server supports the requested usage tag
|
|
412
|
+
if (server.usageList.length === 0 ||
|
|
413
|
+
(usage && server.usageList.includes(usage))) {
|
|
414
|
+
|
|
415
|
+
// Check if server is authoritative for this code system
|
|
416
|
+
const isAuth = server.isAuthCS(codeSystem);
|
|
417
|
+
|
|
418
|
+
server.versions.forEach(version => {
|
|
419
|
+
if (ServerRegistryUtilities.versionMatches(normalizedVersion, version.version)) {
|
|
420
|
+
// Check if the server has the code system
|
|
421
|
+
// Test against both the full URL and the base URL
|
|
422
|
+
let content = {};
|
|
423
|
+
const hasMatchingCS =
|
|
424
|
+
ServerRegistryUtilities.hasMatchingCodeSystem(baseCodeSystem, version.codeSystems, false, content) ||
|
|
425
|
+
(baseCodeSystem !== codeSystem &&
|
|
426
|
+
ServerRegistryUtilities.hasMatchingCodeSystem(codeSystem, version.codeSystems, false, content));
|
|
427
|
+
|
|
428
|
+
if (hasMatchingCS) {
|
|
429
|
+
if (isAuth) {
|
|
430
|
+
result.authoritative.push(this.createServerEntry(server, version));
|
|
431
|
+
} else if (!authoritativeOnly) {
|
|
432
|
+
result.candidates.push(this.createServerEntry(server, version, content.content));
|
|
433
|
+
}
|
|
434
|
+
added = true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
if (added) {
|
|
440
|
+
matchedServers.push(server.code);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// NEW: Fallback - if no matches found, check for authoritative pattern matches
|
|
447
|
+
if (result.authoritative.length === 0 && result.candidates.length === 0) {
|
|
421
448
|
data.registries.forEach(registry => {
|
|
422
449
|
registry.servers.forEach(server => {
|
|
423
|
-
let added = false;
|
|
424
|
-
|
|
425
450
|
// Check if server supports the requested usage tag
|
|
426
451
|
if (server.usageList.length === 0 ||
|
|
427
452
|
(usage && server.usageList.includes(usage))) {
|
|
@@ -429,64 +454,23 @@ class RegistryAPI {
|
|
|
429
454
|
// Check if server is authoritative for this code system
|
|
430
455
|
const isAuth = server.isAuthCS(codeSystem);
|
|
431
456
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
(baseCodeSystem !== codeSystem &&
|
|
439
|
-
ServerRegistryUtilities.hasMatchingCodeSystem(codeSystem, version.codeSystems, false));
|
|
440
|
-
|
|
441
|
-
if (hasMatchingCS) {
|
|
442
|
-
if (isAuth) {
|
|
443
|
-
result.authoritative.push(this.createServerEntry(server, version));
|
|
444
|
-
} else if (!authoritativeOnly) {
|
|
445
|
-
result.candidates.push(this.createServerEntry(server, version));
|
|
457
|
+
if (isAuth) {
|
|
458
|
+
server.versions.forEach(version => {
|
|
459
|
+
if (ServerRegistryUtilities.versionMatches(normalizedVersion, version.version)) {
|
|
460
|
+
result.authoritative.push(this.createServerEntry(server, version));
|
|
461
|
+
if (!matchedServers.includes(server.code)) {
|
|
462
|
+
matchedServers.push(server.code);
|
|
446
463
|
}
|
|
447
|
-
added = true;
|
|
448
464
|
}
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
if (added) {
|
|
453
|
-
matchedServers.push(server.code);
|
|
465
|
+
});
|
|
454
466
|
}
|
|
455
467
|
}
|
|
456
468
|
});
|
|
457
469
|
});
|
|
458
|
-
|
|
459
|
-
// NEW: Fallback - if no matches found, check for authoritative pattern matches
|
|
460
|
-
if (result.authoritative.length === 0 && result.candidates.length === 0) {
|
|
461
|
-
data.registries.forEach(registry => {
|
|
462
|
-
registry.servers.forEach(server => {
|
|
463
|
-
// Check if server supports the requested usage tag
|
|
464
|
-
if (server.usageList.length === 0 ||
|
|
465
|
-
(usage && server.usageList.includes(usage))) {
|
|
466
|
-
|
|
467
|
-
// Check if server is authoritative for this code system
|
|
468
|
-
const isAuth = server.isAuthCS(codeSystem);
|
|
469
|
-
|
|
470
|
-
if (isAuth) {
|
|
471
|
-
server.versions.forEach(version => {
|
|
472
|
-
if (ServerRegistryUtilities.versionMatches(normalizedVersion, version.version)) {
|
|
473
|
-
result.authoritative.push(this.createServerEntry(server, version));
|
|
474
|
-
if (!matchedServers.includes(server.code)) {
|
|
475
|
-
matchedServers.push(server.code);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
} finally {
|
|
485
|
-
data.unlock();
|
|
486
470
|
}
|
|
487
471
|
|
|
488
472
|
return {
|
|
489
|
-
result
|
|
473
|
+
result: this._cleanEmptyArrays(result),
|
|
490
474
|
matches: matchedServers.length > 0 ? matchedServers.join(',') : '--'
|
|
491
475
|
};
|
|
492
476
|
}
|
|
@@ -522,50 +506,45 @@ class RegistryAPI {
|
|
|
522
506
|
}
|
|
523
507
|
|
|
524
508
|
// Lock for thread safety during read
|
|
525
|
-
data.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
registry.servers.forEach(server => {
|
|
529
|
-
let added = false;
|
|
509
|
+
data.registries.forEach(registry => {
|
|
510
|
+
registry.servers.forEach(server => {
|
|
511
|
+
let added = false;
|
|
530
512
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
513
|
+
// Check if server supports the requested usage tag
|
|
514
|
+
if (server.usageList.length === 0 ||
|
|
515
|
+
(usage && server.usageList.includes(usage))) {
|
|
534
516
|
|
|
535
|
-
|
|
536
|
-
|
|
517
|
+
// Check if server is authoritative for this value set
|
|
518
|
+
const isAuth = server.isAuthVS(baseValueSet);
|
|
537
519
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}
|
|
552
|
-
added = true;
|
|
553
|
-
}
|
|
520
|
+
server.versions.forEach(version => {
|
|
521
|
+
if (ServerRegistryUtilities.versionMatches(normalizedVersion, version.version)) {
|
|
522
|
+
// For authoritative servers, we don't need to check if they have the value set
|
|
523
|
+
if (isAuth) {
|
|
524
|
+
result.authoritative.push(this.createServerEntry(server, version));
|
|
525
|
+
added = true;
|
|
526
|
+
}
|
|
527
|
+
// For non-authoritative servers, check if they have the value set
|
|
528
|
+
else if (ServerRegistryUtilities.hasMatchingValueSet(baseValueSet, version.valueSets, false) ||
|
|
529
|
+
(baseValueSet !== valueSet &&
|
|
530
|
+
ServerRegistryUtilities.hasMatchingValueSet(valueSet, version.valueSets, false))) {
|
|
531
|
+
if (!authoritativeOnly) {
|
|
532
|
+
result.candidates.push(this.createServerEntry(server, version));
|
|
554
533
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
if (added) {
|
|
558
|
-
matchedServers.push(server.code);
|
|
534
|
+
added = true;
|
|
535
|
+
}
|
|
559
536
|
}
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
if (added) {
|
|
540
|
+
matchedServers.push(server.code);
|
|
560
541
|
}
|
|
561
|
-
}
|
|
542
|
+
}
|
|
562
543
|
});
|
|
563
|
-
}
|
|
564
|
-
data.unlock();
|
|
565
|
-
}
|
|
544
|
+
});
|
|
566
545
|
|
|
567
546
|
return {
|
|
568
|
-
result
|
|
547
|
+
result: this._cleanEmptyArrays(result),
|
|
569
548
|
matches: matchedServers.length > 0 ? matchedServers.join(',') : '--'
|
|
570
549
|
};
|
|
571
550
|
}
|
|
@@ -598,6 +577,9 @@ class RegistryAPI {
|
|
|
598
577
|
if (server.accessInfo) {
|
|
599
578
|
entry.access_info = server.accessInfo;
|
|
600
579
|
}
|
|
580
|
+
if (version.content) {
|
|
581
|
+
entry.content = version.content;
|
|
582
|
+
}
|
|
601
583
|
|
|
602
584
|
return entry;
|
|
603
585
|
}
|