@atomic-ehr/fhir-canonical-manager 0.0.14 → 0.0.16
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/dist/cache.d.ts +4 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +30 -4
- package/dist/cache.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/local.d.ts +5 -0
- package/dist/local.d.ts.map +1 -0
- package/dist/local.js +148 -0
- package/dist/local.js.map +1 -0
- package/dist/manager/canonical.d.ts.map +1 -1
- package/dist/manager/canonical.js +231 -22
- package/dist/manager/canonical.js.map +1 -1
- package/dist/manager/package-spec.d.ts +5 -0
- package/dist/manager/package-spec.d.ts.map +1 -0
- package/dist/manager/package-spec.js +28 -0
- package/dist/manager/package-spec.js.map +1 -0
- package/dist/package.d.ts.map +1 -1
- package/dist/package.js +25 -5
- package/dist/package.js.map +1 -1
- package/dist/{reference/manager.d.ts → reference.d.ts} +8 -3
- package/dist/reference.d.ts.map +1 -0
- package/dist/{reference/manager.js → reference.js} +7 -2
- package/dist/reference.js.map +1 -0
- package/dist/{resolver/context.d.ts → resolver.d.ts} +3 -3
- package/dist/resolver.d.ts.map +1 -0
- package/dist/{resolver/context.js → resolver.js} +1 -1
- package/dist/resolver.js.map +1 -0
- package/dist/types/core.d.ts +14 -2
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/internal.d.ts +4 -2
- package/dist/types/internal.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/reference/index.d.ts +0 -4
- package/dist/reference/index.d.ts.map +0 -1
- package/dist/reference/index.js +0 -3
- package/dist/reference/index.js.map +0 -1
- package/dist/reference/manager.d.ts.map +0 -1
- package/dist/reference/manager.js.map +0 -1
- package/dist/reference/store.d.ts +0 -6
- package/dist/reference/store.d.ts.map +0 -1
- package/dist/reference/store.js +0 -6
- package/dist/reference/store.js.map +0 -1
- package/dist/resolver/context.d.ts.map +0 -1
- package/dist/resolver/context.js.map +0 -1
- package/dist/resolver/index.d.ts +0 -2
- package/dist/resolver/index.d.ts.map +0 -1
- package/dist/resolver/index.js +0 -2
- package/dist/resolver/index.js.map +0 -1
- package/src/cache.ts +0 -58
- package/src/cli/index.ts +0 -181
- package/src/cli/init.ts +0 -112
- package/src/cli/list.ts +0 -95
- package/src/cli/resolve.ts +0 -63
- package/src/cli/search.ts +0 -83
- package/src/cli/searchparam.ts +0 -163
- package/src/constants.ts +0 -6
- package/src/fs/index.ts +0 -5
- package/src/fs/utils.ts +0 -28
- package/src/index.ts +0 -18
- package/src/manager/canonical.ts +0 -327
- package/src/manager/index.ts +0 -6
- package/src/package.ts +0 -79
- package/src/reference/index.ts +0 -8
- package/src/reference/manager.ts +0 -55
- package/src/reference/store.ts +0 -14
- package/src/resolver/context.ts +0 -25
- package/src/resolver/index.ts +0 -5
- package/src/scanner/directory.ts +0 -36
- package/src/scanner/index.ts +0 -8
- package/src/scanner/package.ts +0 -35
- package/src/scanner/parser.ts +0 -40
- package/src/scanner/processor.ts +0 -65
- package/src/search/index.ts +0 -6
- package/src/search/smart.ts +0 -50
- package/src/search/terms.ts +0 -22
- package/src/types/core.ts +0 -131
- package/src/types/index.ts +0 -6
- package/src/types/internal.ts +0 -59
package/src/cli/index.ts
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import * as fs from "node:fs";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import type { Config } from "../index.js";
|
|
7
|
-
|
|
8
|
-
// Command handlers
|
|
9
|
-
import { initCommand } from "./init.js";
|
|
10
|
-
import { listCommand } from "./list.js";
|
|
11
|
-
import { resolveCommand } from "./resolve.js";
|
|
12
|
-
import { searchCommand } from "./search.js";
|
|
13
|
-
import { searchParamCommand } from "./searchparam.js";
|
|
14
|
-
|
|
15
|
-
// Get version from package.json
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
-
const __dirname = path.dirname(__filename);
|
|
18
|
-
const packageJsonPath = path.join(__dirname, "..", "..", "package.json");
|
|
19
|
-
|
|
20
|
-
let VERSION = "unknown";
|
|
21
|
-
try {
|
|
22
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
23
|
-
VERSION = packageJson.version;
|
|
24
|
-
} catch (_error) {
|
|
25
|
-
// Fallback version if package.json can't be read
|
|
26
|
-
VERSION = "0.0.3";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function showHelp() {
|
|
30
|
-
console.log(`
|
|
31
|
-
fcm - FHIR Canonical Manager CLI
|
|
32
|
-
|
|
33
|
-
Usage: fcm <command> [options]
|
|
34
|
-
|
|
35
|
-
Commands:
|
|
36
|
-
init Initialize FHIR packages in current directory
|
|
37
|
-
list List packages or resources
|
|
38
|
-
search Search for resources
|
|
39
|
-
resolve Get a resource by canonical URL
|
|
40
|
-
searchparam Display search parameters for a resource type
|
|
41
|
-
|
|
42
|
-
Options:
|
|
43
|
-
--help Show help
|
|
44
|
-
--version Show version
|
|
45
|
-
|
|
46
|
-
Examples:
|
|
47
|
-
fcm init hl7.fhir.r4.core
|
|
48
|
-
fcm list
|
|
49
|
-
fcm search Patient
|
|
50
|
-
fcm resolve http://hl7.org/fhir/StructureDefinition/Patient
|
|
51
|
-
fcm searchparam Patient
|
|
52
|
-
`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function main() {
|
|
56
|
-
const args = process.argv.slice(2);
|
|
57
|
-
const command = args[0];
|
|
58
|
-
|
|
59
|
-
if (!command || command === "--help" || command === "-h") {
|
|
60
|
-
showHelp();
|
|
61
|
-
if (process.env.NODE_ENV === "test") {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
process.exit(0);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (command === "--version" || command === "-v") {
|
|
68
|
-
console.log(VERSION);
|
|
69
|
-
if (process.env.NODE_ENV === "test") {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
process.exit(0);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const commands: Record<string, (args: string[]) => Promise<void>> = {
|
|
76
|
-
init: initCommand,
|
|
77
|
-
list: listCommand,
|
|
78
|
-
search: searchCommand,
|
|
79
|
-
resolve: resolveCommand,
|
|
80
|
-
searchparam: searchParamCommand,
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
if (!commands[command]) {
|
|
84
|
-
console.error(`Error: Unknown command '${command}'`);
|
|
85
|
-
console.error(`Run 'fcm --help' for usage information`);
|
|
86
|
-
if (process.env.NODE_ENV === "test") {
|
|
87
|
-
throw new Error(`Unknown command '${command}'`);
|
|
88
|
-
}
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
await commands[command](args.slice(1));
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
-
if (process.env.NODE_ENV === "test") {
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Export utility functions for commands
|
|
104
|
-
export function parseArgs(args: string[]): {
|
|
105
|
-
positional: string[];
|
|
106
|
-
options: Record<string, string | boolean>;
|
|
107
|
-
} {
|
|
108
|
-
const positional: string[] = [];
|
|
109
|
-
const options: Record<string, string | boolean> = {};
|
|
110
|
-
|
|
111
|
-
for (let i = 0; i < args.length; i++) {
|
|
112
|
-
const arg = args[i];
|
|
113
|
-
if (arg?.startsWith("--")) {
|
|
114
|
-
const key = arg.slice(2);
|
|
115
|
-
const nextArg = args[i + 1];
|
|
116
|
-
if (nextArg && !nextArg.startsWith("--")) {
|
|
117
|
-
options[key] = nextArg;
|
|
118
|
-
i++;
|
|
119
|
-
} else {
|
|
120
|
-
options[key] = true;
|
|
121
|
-
}
|
|
122
|
-
} else if (arg?.startsWith("-")) {
|
|
123
|
-
// Handle short aliases
|
|
124
|
-
switch (arg) {
|
|
125
|
-
case "-sd":
|
|
126
|
-
options.resourceType = "StructureDefinition";
|
|
127
|
-
break;
|
|
128
|
-
case "-cs":
|
|
129
|
-
options.resourceType = "CodeSystem";
|
|
130
|
-
break;
|
|
131
|
-
case "-vs":
|
|
132
|
-
options.resourceType = "ValueSet";
|
|
133
|
-
break;
|
|
134
|
-
default: {
|
|
135
|
-
// Handle other single-letter flags
|
|
136
|
-
const key = arg.slice(1);
|
|
137
|
-
const nextArg = args[i + 1];
|
|
138
|
-
if (nextArg && !nextArg.startsWith("-")) {
|
|
139
|
-
options[key] = nextArg;
|
|
140
|
-
i++;
|
|
141
|
-
} else {
|
|
142
|
-
options[key] = true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} else if (arg) {
|
|
147
|
-
positional.push(arg);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return { positional, options };
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export async function loadPackageJson(): Promise<any> {
|
|
155
|
-
const packagePath = path.join(process.cwd(), "package.json");
|
|
156
|
-
try {
|
|
157
|
-
if (fs.existsSync(packagePath)) {
|
|
158
|
-
const content = fs.readFileSync(packagePath, "utf-8");
|
|
159
|
-
return JSON.parse(content);
|
|
160
|
-
}
|
|
161
|
-
} catch (_error) {
|
|
162
|
-
// Ignore parse errors
|
|
163
|
-
}
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export async function savePackageJson(data: any): Promise<void> {
|
|
168
|
-
const packagePath = path.join(process.cwd(), "package.json");
|
|
169
|
-
fs.writeFileSync(packagePath, `${JSON.stringify(data, null, 2)}\n`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function getConfigFromPackageJson(packageJson: any): Partial<Config> {
|
|
173
|
-
const fcm = packageJson?.fcm || {};
|
|
174
|
-
return {
|
|
175
|
-
packages: fcm.packages || [],
|
|
176
|
-
registry: fcm.registry,
|
|
177
|
-
workingDir: process.cwd(),
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
main();
|
package/src/cli/init.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { promisify } from "node:util";
|
|
4
|
-
import { CanonicalManager } from "../index.js";
|
|
5
|
-
import { loadPackageJson, parseArgs, savePackageJson } from "./index.js";
|
|
6
|
-
|
|
7
|
-
const execAsync = promisify(exec);
|
|
8
|
-
|
|
9
|
-
export async function initCommand(args: string[]): Promise<void> {
|
|
10
|
-
const { positional, options } = parseArgs(args);
|
|
11
|
-
const packages = positional;
|
|
12
|
-
const registry = options.registry as string | undefined;
|
|
13
|
-
|
|
14
|
-
// Load or create package.json
|
|
15
|
-
let packageJson = await loadPackageJson();
|
|
16
|
-
const isNewPackageJson = !packageJson;
|
|
17
|
-
|
|
18
|
-
if (!packageJson) {
|
|
19
|
-
// Create minimal package.json
|
|
20
|
-
packageJson = {
|
|
21
|
-
name: path.basename(process.cwd()),
|
|
22
|
-
version: "1.0.0",
|
|
23
|
-
type: "module",
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Initialize fcm config
|
|
28
|
-
if (!packageJson.fcm) {
|
|
29
|
-
packageJson.fcm = {
|
|
30
|
-
packages: [],
|
|
31
|
-
registry: registry ? (registry.endsWith("/") ? registry : `${registry}/`) : "https://fs.get-ig.org/pkgs/",
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// If no packages specified, use packages from config
|
|
36
|
-
const packagesToInstall = packages.length > 0 ? packages : packageJson.fcm.packages;
|
|
37
|
-
|
|
38
|
-
if (packagesToInstall.length === 0) {
|
|
39
|
-
console.error("Error: No packages specified");
|
|
40
|
-
console.error("Usage: fcm init [packages...]");
|
|
41
|
-
console.error("Example: fcm init hl7.fhir.r4.core hl7.fhir.us.core@5.0.1");
|
|
42
|
-
if (process.env.NODE_ENV === "test") {
|
|
43
|
-
throw new Error("No packages specified");
|
|
44
|
-
}
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Update fcm packages list (merge with existing)
|
|
49
|
-
const existingPackages = new Set(packageJson.fcm.packages);
|
|
50
|
-
packagesToInstall.forEach((pkg: string) => {
|
|
51
|
-
existingPackages.add(pkg);
|
|
52
|
-
});
|
|
53
|
-
packageJson.fcm.packages = Array.from(existingPackages);
|
|
54
|
-
|
|
55
|
-
// Update registry if provided, ensuring it ends with /
|
|
56
|
-
if (registry) {
|
|
57
|
-
packageJson.fcm.registry = registry.endsWith("/") ? registry : `${registry}/`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Initialize dependencies if not present
|
|
61
|
-
if (!packageJson.dependencies) {
|
|
62
|
-
packageJson.dependencies = {};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Save package.json
|
|
66
|
-
await savePackageJson(packageJson);
|
|
67
|
-
|
|
68
|
-
if (isNewPackageJson) {
|
|
69
|
-
console.log("Created package.json");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Install packages using npm
|
|
73
|
-
console.log("Installing FHIR packages...");
|
|
74
|
-
|
|
75
|
-
for (const pkg of packagesToInstall) {
|
|
76
|
-
console.log(`Installing ${pkg}...`);
|
|
77
|
-
try {
|
|
78
|
-
const command = packageJson.fcm.registry
|
|
79
|
-
? `npm install ${pkg} --registry ${packageJson.fcm.registry}`
|
|
80
|
-
: `npm install ${pkg}`;
|
|
81
|
-
|
|
82
|
-
await execAsync(command, {
|
|
83
|
-
cwd: process.cwd(),
|
|
84
|
-
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
85
|
-
});
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.error(`Failed to install ${pkg}`);
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Initialize CanonicalManager to build cache
|
|
93
|
-
console.log("Building package index...");
|
|
94
|
-
console.log("Registry", packageJson?.fcm?.registry);
|
|
95
|
-
const manager = CanonicalManager({
|
|
96
|
-
packages: packageJson.fcm.packages,
|
|
97
|
-
workingDir: process.cwd(),
|
|
98
|
-
registry: packageJson.fcm.registry,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
await manager.init();
|
|
102
|
-
|
|
103
|
-
// Show summary
|
|
104
|
-
const installedPackages = await manager.packages();
|
|
105
|
-
console.log("\nInstalled packages:");
|
|
106
|
-
installedPackages.forEach((pkg) => {
|
|
107
|
-
console.log(` ${pkg.name}@${pkg.version}`);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
await manager.destroy();
|
|
111
|
-
console.log("\nInitialization complete!");
|
|
112
|
-
}
|
package/src/cli/list.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { CanonicalManager } from "../index.js";
|
|
2
|
-
import { getConfigFromPackageJson, loadPackageJson, parseArgs } from "./index.js";
|
|
3
|
-
|
|
4
|
-
export async function listCommand(args: string[]): Promise<void> {
|
|
5
|
-
const { positional, options } = parseArgs(args);
|
|
6
|
-
const packageName = positional[0];
|
|
7
|
-
const isJson = options.json === true;
|
|
8
|
-
const typeFilter = options.type as string | undefined;
|
|
9
|
-
|
|
10
|
-
// Load config from package.json
|
|
11
|
-
const packageJson = await loadPackageJson();
|
|
12
|
-
if (!packageJson?.fcm?.packages || packageJson.fcm.packages.length === 0) {
|
|
13
|
-
console.error("Error: No FHIR packages configured");
|
|
14
|
-
console.error("Run 'fcm init' first to initialize packages");
|
|
15
|
-
if (process.env.NODE_ENV === "test") {
|
|
16
|
-
throw new Error("No FHIR packages configured");
|
|
17
|
-
}
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const config = getConfigFromPackageJson(packageJson);
|
|
22
|
-
const manager = CanonicalManager(config as any);
|
|
23
|
-
await manager.init();
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
if (!packageName) {
|
|
27
|
-
// List all packages
|
|
28
|
-
const packages = await manager.packages();
|
|
29
|
-
|
|
30
|
-
if (isJson) {
|
|
31
|
-
console.log(JSON.stringify(packages, null, 2));
|
|
32
|
-
} else {
|
|
33
|
-
console.log("Packages:");
|
|
34
|
-
packages.forEach((pkg) => {
|
|
35
|
-
console.log(` ${pkg.name}@${pkg.version}`);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
// List resources in a specific package
|
|
40
|
-
const packages = await manager.packages();
|
|
41
|
-
const pkg = packages.find((p) => p.name === packageName);
|
|
42
|
-
|
|
43
|
-
if (!pkg) {
|
|
44
|
-
console.error(`Error: Package '${packageName}' not found`);
|
|
45
|
-
console.error("Available packages:");
|
|
46
|
-
packages.forEach((p) => {
|
|
47
|
-
console.error(` - ${p.name}`);
|
|
48
|
-
});
|
|
49
|
-
if (process.env.NODE_ENV === "test") {
|
|
50
|
-
throw new Error(`Package '${packageName}' not found`);
|
|
51
|
-
}
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let resources = await manager.searchEntries({ package: pkg });
|
|
56
|
-
|
|
57
|
-
// Apply type filter if specified
|
|
58
|
-
if (typeFilter) {
|
|
59
|
-
resources = resources.filter((r) => r.resourceType === typeFilter);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (isJson) {
|
|
63
|
-
console.log(JSON.stringify(resources, null, 2));
|
|
64
|
-
} else {
|
|
65
|
-
console.log(`Resources in ${packageName}:`);
|
|
66
|
-
|
|
67
|
-
if (resources.length === 0) {
|
|
68
|
-
console.log(" No resources found");
|
|
69
|
-
} else {
|
|
70
|
-
// Group by type
|
|
71
|
-
const byType = resources.reduce(
|
|
72
|
-
(acc, resource) => {
|
|
73
|
-
const type = resource.resourceType || resource.type || "Unknown";
|
|
74
|
-
if (!acc[type]) acc[type] = 0;
|
|
75
|
-
acc[type]++;
|
|
76
|
-
return acc;
|
|
77
|
-
},
|
|
78
|
-
{} as Record<string, number>,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
// Show summary
|
|
82
|
-
Object.entries(byType)
|
|
83
|
-
.sort()
|
|
84
|
-
.forEach(([type, count]) => {
|
|
85
|
-
console.log(` ${type}: ${count}`);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
console.log(`\nTotal: ${resources.length} resources`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
} finally {
|
|
93
|
-
await manager.destroy();
|
|
94
|
-
}
|
|
95
|
-
}
|
package/src/cli/resolve.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { CanonicalManager } from "../index.js";
|
|
2
|
-
import { getConfigFromPackageJson, loadPackageJson, parseArgs } from "./index.js";
|
|
3
|
-
|
|
4
|
-
export async function resolveCommand(args: string[]): Promise<void> {
|
|
5
|
-
const { positional, options } = parseArgs(args);
|
|
6
|
-
const url = positional[0];
|
|
7
|
-
const fields = options.fields as string | undefined;
|
|
8
|
-
|
|
9
|
-
if (!url) {
|
|
10
|
-
console.error("Error: Canonical URL required");
|
|
11
|
-
console.error("Usage: fcm resolve <canonical-url> [--fields field1,field2]");
|
|
12
|
-
console.error("Example: fcm resolve http://hl7.org/fhir/StructureDefinition/Patient");
|
|
13
|
-
if (process.env.NODE_ENV === "test") {
|
|
14
|
-
throw new Error("Canonical URL required");
|
|
15
|
-
}
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Load config from package.json
|
|
20
|
-
const packageJson = await loadPackageJson();
|
|
21
|
-
if (!packageJson?.fcm?.packages || packageJson.fcm.packages.length === 0) {
|
|
22
|
-
console.error("Error: No FHIR packages configured");
|
|
23
|
-
console.error("Run 'fcm init' first to initialize packages");
|
|
24
|
-
if (process.env.NODE_ENV === "test") {
|
|
25
|
-
throw new Error("No FHIR packages configured");
|
|
26
|
-
}
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const config = getConfigFromPackageJson(packageJson);
|
|
31
|
-
const manager = CanonicalManager(config as any);
|
|
32
|
-
await manager.init();
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
// Resolve the resource
|
|
36
|
-
const resource = await manager.resolve(url);
|
|
37
|
-
|
|
38
|
-
if (fields) {
|
|
39
|
-
// Extract only specified fields
|
|
40
|
-
const fieldList = fields.split(",").map((f) => f.trim());
|
|
41
|
-
const filtered: any = {};
|
|
42
|
-
|
|
43
|
-
fieldList.forEach((field) => {
|
|
44
|
-
if (field in resource) {
|
|
45
|
-
filtered[field] = resource[field];
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
console.log(JSON.stringify(filtered, null, 2));
|
|
50
|
-
} else {
|
|
51
|
-
// Output full resource
|
|
52
|
-
console.log(JSON.stringify(resource, null, 2));
|
|
53
|
-
}
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error(`Error: Resource not found: ${url}`);
|
|
56
|
-
if (process.env.NODE_ENV === "test") {
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
process.exit(1);
|
|
60
|
-
} finally {
|
|
61
|
-
await manager.destroy();
|
|
62
|
-
}
|
|
63
|
-
}
|
package/src/cli/search.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { CanonicalManager } from "../index.js";
|
|
2
|
-
import { getConfigFromPackageJson, loadPackageJson, parseArgs } from "./index.js";
|
|
3
|
-
|
|
4
|
-
export async function searchCommand(args: string[]): Promise<void> {
|
|
5
|
-
const { positional, options } = parseArgs(args);
|
|
6
|
-
const searchTerms = positional; // Now support multiple search terms
|
|
7
|
-
const isJson = options.json === true;
|
|
8
|
-
const resourceTypeFilter = (options.type || options.resourceType) as string | undefined;
|
|
9
|
-
const typeFilter = options.t as string | undefined;
|
|
10
|
-
const kindFilter = options.k as string | undefined;
|
|
11
|
-
const packageFilter = options.package as string | undefined;
|
|
12
|
-
|
|
13
|
-
// Load config from package.json
|
|
14
|
-
const packageJson = await loadPackageJson();
|
|
15
|
-
if (!packageJson?.fcm?.packages || packageJson.fcm.packages.length === 0) {
|
|
16
|
-
console.error("Error: No FHIR packages configured");
|
|
17
|
-
console.error("Run 'fcm init' first to initialize packages");
|
|
18
|
-
if (process.env.NODE_ENV === "test" || process.env.BUN_TEST) {
|
|
19
|
-
throw new Error("No FHIR packages configured");
|
|
20
|
-
}
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const config = getConfigFromPackageJson(packageJson);
|
|
25
|
-
const manager = CanonicalManager(config as any);
|
|
26
|
-
await manager.init();
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// Build filters for smart search
|
|
30
|
-
const filters: any = {};
|
|
31
|
-
|
|
32
|
-
if (resourceTypeFilter) {
|
|
33
|
-
filters.resourceType = resourceTypeFilter;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (typeFilter) {
|
|
37
|
-
filters.type = typeFilter;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (kindFilter) {
|
|
41
|
-
filters.kind = kindFilter;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (packageFilter) {
|
|
45
|
-
const packages = await manager.packages();
|
|
46
|
-
const pkg = packages.find((p) => p.name === packageFilter);
|
|
47
|
-
if (!pkg) {
|
|
48
|
-
console.error(`Error: Package '${packageFilter}' not found`);
|
|
49
|
-
if (process.env.NODE_ENV === "test" || process.env.BUN_TEST) {
|
|
50
|
-
throw new Error(`Package '${packageFilter}' not found`);
|
|
51
|
-
}
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
filters.package = pkg;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Use the new smartSearch from core
|
|
58
|
-
const results = await manager.smartSearch(searchTerms, filters);
|
|
59
|
-
|
|
60
|
-
if (isJson) {
|
|
61
|
-
console.log(JSON.stringify(results, null, 2));
|
|
62
|
-
} else {
|
|
63
|
-
if (results.length === 0) {
|
|
64
|
-
console.log("No resources found");
|
|
65
|
-
} else {
|
|
66
|
-
const searchInfo = searchTerms.length > 0 ? ` matching "${searchTerms.join(" ")}"` : "";
|
|
67
|
-
console.log(`Found ${results.length} resource${results.length === 1 ? "" : "s"}${searchInfo}:`);
|
|
68
|
-
|
|
69
|
-
results.forEach((resource) => {
|
|
70
|
-
const info = {
|
|
71
|
-
resourceType: resource.resourceType,
|
|
72
|
-
kind: resource.kind,
|
|
73
|
-
type: resource.type,
|
|
74
|
-
package: resource.package?.name,
|
|
75
|
-
};
|
|
76
|
-
console.log(`${resource.url}, ${JSON.stringify(info)}`);
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
} finally {
|
|
81
|
-
await manager.destroy();
|
|
82
|
-
}
|
|
83
|
-
}
|
package/src/cli/searchparam.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search parameters command - displays search parameters for a resource type
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { CanonicalManager } from "../index.js";
|
|
6
|
-
import type { SearchParameter } from "../types/index.js";
|
|
7
|
-
import { getConfigFromPackageJson, loadPackageJson, parseArgs } from "./index.js";
|
|
8
|
-
|
|
9
|
-
export async function searchParamCommand(args: string[]): Promise<void> {
|
|
10
|
-
const { positional, options } = parseArgs(args);
|
|
11
|
-
|
|
12
|
-
if (options.help || positional.length === 0) {
|
|
13
|
-
console.log(`
|
|
14
|
-
Usage: fcm searchparam <resourceType> [options]
|
|
15
|
-
|
|
16
|
-
Display search parameters for a specific FHIR resource type
|
|
17
|
-
|
|
18
|
-
Arguments:
|
|
19
|
-
resourceType The FHIR resource type (e.g., Patient, Observation)
|
|
20
|
-
|
|
21
|
-
Options:
|
|
22
|
-
--format Output format: table (default), json, csv
|
|
23
|
-
--help Show this help message
|
|
24
|
-
|
|
25
|
-
Examples:
|
|
26
|
-
fcm searchparam Patient
|
|
27
|
-
fcm searchparam Observation --format json
|
|
28
|
-
fcm searchparam Encounter --format csv
|
|
29
|
-
`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const resourceType = positional[0];
|
|
34
|
-
if (!resourceType) {
|
|
35
|
-
console.error("Error: Resource type is required");
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
const format = (options.format as string) || "table";
|
|
39
|
-
|
|
40
|
-
// Load config from package.json
|
|
41
|
-
const packageJson = await loadPackageJson();
|
|
42
|
-
if (!packageJson) {
|
|
43
|
-
throw new Error("No package.json found. Run 'fcm init' to initialize a project.");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const config = getConfigFromPackageJson(packageJson);
|
|
47
|
-
const manager = CanonicalManager({
|
|
48
|
-
packages: config.packages || [],
|
|
49
|
-
registry: config.registry,
|
|
50
|
-
workingDir: config.workingDir || process.cwd(),
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
await manager.init();
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const searchParams = await manager.getSearchParametersForResource(resourceType);
|
|
57
|
-
|
|
58
|
-
if (searchParams.length === 0) {
|
|
59
|
-
console.log(`No search parameters found for resource type '${resourceType}'`);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Format output based on requested format
|
|
64
|
-
switch (format) {
|
|
65
|
-
case "json":
|
|
66
|
-
outputJson(searchParams);
|
|
67
|
-
break;
|
|
68
|
-
case "csv":
|
|
69
|
-
outputCsv(searchParams);
|
|
70
|
-
break;
|
|
71
|
-
default:
|
|
72
|
-
outputTable(searchParams);
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
} finally {
|
|
76
|
-
await manager.destroy();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function outputTable(searchParams: SearchParameter[]): void {
|
|
81
|
-
console.log("");
|
|
82
|
-
|
|
83
|
-
// Display each parameter as a multiline block
|
|
84
|
-
for (const param of searchParams) {
|
|
85
|
-
const code = param.code || "";
|
|
86
|
-
const type = param.type || "";
|
|
87
|
-
const expression = param.expression || "";
|
|
88
|
-
const url = param.url || "";
|
|
89
|
-
|
|
90
|
-
console.log(`Code: ${code}`);
|
|
91
|
-
console.log(`Type: ${type}`);
|
|
92
|
-
if (expression) {
|
|
93
|
-
// Wrap long expressions
|
|
94
|
-
if (expression.length > 60) {
|
|
95
|
-
console.log(`Expression: ${wrapText(expression, 60, " ")}`);
|
|
96
|
-
} else {
|
|
97
|
-
console.log(`Expression: ${expression}`);
|
|
98
|
-
}
|
|
99
|
-
} else {
|
|
100
|
-
console.log(`Expression: (none)`);
|
|
101
|
-
}
|
|
102
|
-
console.log(`URL: ${url}`);
|
|
103
|
-
console.log("---");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
console.log(`Total: ${searchParams.length} search parameters`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Helper function to wrap text at specified width
|
|
110
|
-
function wrapText(text: string, width: number, indent: string): string {
|
|
111
|
-
const words = text.split(" ");
|
|
112
|
-
const lines: string[] = [];
|
|
113
|
-
let currentLine = "";
|
|
114
|
-
|
|
115
|
-
for (const word of words) {
|
|
116
|
-
if (currentLine.length + word.length + 1 <= width) {
|
|
117
|
-
currentLine += (currentLine ? " " : "") + word;
|
|
118
|
-
} else {
|
|
119
|
-
if (currentLine) {
|
|
120
|
-
lines.push(currentLine);
|
|
121
|
-
}
|
|
122
|
-
currentLine = word;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (currentLine) {
|
|
127
|
-
lines.push(currentLine);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return lines.join(`\n${indent}`);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function outputJson(searchParams: SearchParameter[]): void {
|
|
134
|
-
const output = searchParams.map((param) => ({
|
|
135
|
-
code: param.code,
|
|
136
|
-
type: param.type,
|
|
137
|
-
expression: param.expression || null,
|
|
138
|
-
url: param.url,
|
|
139
|
-
}));
|
|
140
|
-
console.log(JSON.stringify(output, null, 2));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function outputCsv(searchParams: SearchParameter[]): void {
|
|
144
|
-
// CSV header
|
|
145
|
-
console.log("Code,Type,Expression,URL");
|
|
146
|
-
|
|
147
|
-
// CSV rows - no truncation for CSV output
|
|
148
|
-
for (const param of searchParams) {
|
|
149
|
-
const code = escapeCsv(param.code || "");
|
|
150
|
-
const type = escapeCsv(param.type || "");
|
|
151
|
-
const expression = escapeCsv(param.expression || "");
|
|
152
|
-
const url = escapeCsv(param.url || "");
|
|
153
|
-
console.log(`${code},${type},${expression},${url}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function escapeCsv(value: string): string {
|
|
158
|
-
// Escape CSV values that contain commas, quotes, or newlines
|
|
159
|
-
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
160
|
-
return `"${value.replace(/"/g, '""')}"`;
|
|
161
|
-
}
|
|
162
|
-
return value;
|
|
163
|
-
}
|