fhir-openapi-translator 0.1.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.
@@ -0,0 +1,253 @@
1
+ type FhirVersion = "r4" | "r4b" | "r5";
2
+ declare const FHIR_VERSIONS: readonly FhirVersion[];
3
+ declare const FHIR_VERSION_NUMBERS: Record<FhirVersion, string>;
4
+ type OpenApiVersion = "3.0.3" | "3.1.0";
5
+ type SourceBackend = "schema-json" | "structure-def";
6
+ interface TrimOptions {
7
+ /**
8
+ * Replace the Narrative type (human-readable HTML in `Resource.text`) with a
9
+ * generic object. Shrinks generated models that never render narratives.
10
+ */
11
+ excludeNarrative?: boolean;
12
+ /**
13
+ * Stub out schema definitions first reached deeper than this many hops from
14
+ * a requested resource with a generic object. Bounds the size of the
15
+ * dependency closure for codegen targets that struggle with large graphs.
16
+ */
17
+ maxDepth?: number;
18
+ /**
19
+ * Replace required-binding enums on code fields with plain strings (the
20
+ * allowed codes are appended to the description). Codegen'd models then
21
+ * tolerate servers that return codes outside the strict ValueSet — a common
22
+ * reality with legacy data. `resourceType` discriminators keep their enum.
23
+ */
24
+ noEnums?: boolean;
25
+ }
26
+ /** An IG package resolved to profiles + terminology (see ig/package.ts). */
27
+ interface IgContextLike {
28
+ name: string;
29
+ version: string;
30
+ fhirVersion: FhirVersion;
31
+ profiles: unknown[];
32
+ profilesMissingSnapshot: string[];
33
+ resolveValueSet: (valueSetUrl: string) => string[] | undefined;
34
+ }
35
+ /** A parsed CapabilityStatement (see capability.ts). */
36
+ interface CapabilityLike {
37
+ fhirVersion?: string;
38
+ resources: {
39
+ type: string;
40
+ interactions: Set<string>;
41
+ searchParamCodes: Set<string>;
42
+ operations: Set<string>;
43
+ }[];
44
+ }
45
+ interface GenerateOptions {
46
+ /**
47
+ * FHIR resource names, e.g. ["Patient", "Observation"]. Optional when a
48
+ * `capability` statement is given (its declared resources are used); when
49
+ * both are set, generation is narrowed to the requested resources.
50
+ */
51
+ resources?: string[];
52
+ fhirVersion: FhirVersion;
53
+ /**
54
+ * A parsed CapabilityStatement restricting generation to one server's
55
+ * declared support (resources, interactions, search params, operations).
56
+ * Use `loadCapabilityStatement` / `parseCapabilityStatement` to build it.
57
+ */
58
+ capability?: CapabilityLike;
59
+ /**
60
+ * IG package to apply profiles from: a local path (`.tgz` or unpacked
61
+ * directory) loaded synchronously, or a pre-resolved IgContext (use the
62
+ * async `loadIg` for registry coordinates). Required when `profiles` is set.
63
+ */
64
+ ig?: string | IgContextLike;
65
+ /**
66
+ * Profile ids, names, or canonical URLs to apply to their base resources.
67
+ * Each profiled resource's schemas/paths reference the named profile schema.
68
+ */
69
+ profiles?: string[];
70
+ /** Target OpenAPI version. Default: "3.0.3" (widest codegen support). */
71
+ openApiVersion?: OpenApiVersion;
72
+ /** Definition source backend. Default: "schema-json". */
73
+ source?: SourceBackend;
74
+ /**
75
+ * Also emit the standard FHIR operations applicable to the requested
76
+ * resources ($everything, $validate, ...) from the official
77
+ * OperationDefinitions. Default: false.
78
+ */
79
+ operations?: boolean;
80
+ /** Server base URL for the `servers` entry. Omitted when not given. */
81
+ baseUrl?: string;
82
+ /** Override the generated `info.title`. */
83
+ title?: string;
84
+ trim?: TrimOptions;
85
+ }
86
+ /** A generated OpenAPI document (3.0.3 or 3.1.0) as a plain object. */
87
+ type OpenApiDocument = {
88
+ [key: string]: unknown;
89
+ };
90
+
91
+ /** Lists the resource type names available for a FHIR version. */
92
+ declare function listResources(fhirVersion: FhirVersion, source?: SourceBackend): string[];
93
+ /**
94
+ * Generates an OpenAPI document covering the requested FHIR resources: their
95
+ * full schema dependency closure plus the standard FHIR RESTful interactions.
96
+ */
97
+ declare function generateOpenApi(options: GenerateOptions): OpenApiDocument;
98
+
99
+ /** FHIR RESTful interaction codes (CapabilityStatement.rest.resource.interaction). */
100
+ type FhirInteraction = "read" | "vread" | "update" | "patch" | "delete" | "history-instance" | "history-type" | "create" | "search-type";
101
+
102
+ /**
103
+ * Loads and parses a FHIR CapabilityStatement (a server's `/metadata`) into a
104
+ * per-resource description of what the server actually supports, so a spec can
105
+ * be generated to match exactly one server's surface rather than the full
106
+ * standard interaction set.
107
+ */
108
+ interface ResourceCapability {
109
+ type: string;
110
+ interactions: Set<FhirInteraction>;
111
+ /** Search parameter codes the server declares for this resource. */
112
+ searchParamCodes: Set<string>;
113
+ /** Operation codes and canonical URLs the server declares for this resource. */
114
+ operations: Set<string>;
115
+ }
116
+ interface Capability {
117
+ /** FHIR version string from the statement, e.g. "4.0.1" (may be undefined). */
118
+ fhirVersion?: string;
119
+ resources: ResourceCapability[];
120
+ }
121
+ interface LoadCapabilityOptions {
122
+ fetchImpl?: typeof fetch;
123
+ }
124
+ /**
125
+ * Loads a CapabilityStatement from a local JSON file or an http(s) URL. A URL
126
+ * that does not already end in `/metadata` has it appended, so a base server
127
+ * URL works directly.
128
+ */
129
+ declare function loadCapabilityStatement(input: string, options?: LoadCapabilityOptions): Promise<Capability>;
130
+ declare function parseCapabilityStatement(json: unknown): Capability;
131
+
132
+ interface MinElementType {
133
+ code: string;
134
+ targetProfile?: string[];
135
+ fhirType?: string;
136
+ }
137
+ interface MinElement {
138
+ path: string;
139
+ min: number;
140
+ max: string;
141
+ short?: string;
142
+ definition?: string;
143
+ contentReference?: string;
144
+ types?: MinElementType[];
145
+ binding?: {
146
+ strength: string;
147
+ valueSet: string;
148
+ codes?: string[];
149
+ };
150
+ /**
151
+ * Value the element is fixed to by a profile (`fixed[x]`), normalized to a
152
+ * JSON value. Only populated for profiles loaded from an IG package; the
153
+ * vendored base definitions do not carry it.
154
+ */
155
+ fixed?: unknown;
156
+ /** Profile `mustSupport` flag (surfaced in descriptions, not enforced). */
157
+ mustSupport?: boolean;
158
+ /**
159
+ * Human labels for profile constraints this tool does not enforce in
160
+ * OpenAPI (e.g. "pattern", "slicing"), surfaced in the property description
161
+ * and `x-fhir-constraints-omitted`. IG profiles only.
162
+ */
163
+ omittedConstraints?: string[];
164
+ }
165
+ interface MinStructureDefinition {
166
+ name: string;
167
+ url: string;
168
+ kind: "resource" | "complex-type" | "primitive-type";
169
+ type: string;
170
+ abstract: boolean;
171
+ baseDefinition?: string;
172
+ elements: MinElement[];
173
+ }
174
+
175
+ type ValueSetResolver = (valueSetUrl: string) => string[] | undefined;
176
+
177
+ interface IgProfile {
178
+ /** Versionless canonical URL. */
179
+ url: string;
180
+ id?: string;
181
+ name: string;
182
+ type: string;
183
+ definition: MinStructureDefinition;
184
+ }
185
+ interface IgContext {
186
+ name: string;
187
+ version: string;
188
+ fhirVersion: FhirVersion;
189
+ profiles: IgProfile[];
190
+ /** Names/URLs of constraint profiles that lack a snapshot (cannot be applied). */
191
+ profilesMissingSnapshot: string[];
192
+ resolveValueSet: ValueSetResolver;
193
+ }
194
+ interface LoadIgOptions {
195
+ /** Resolve core bindings (e.g. administrative-gender) not defined in the IG. */
196
+ coreValueSetFallback?: ValueSetResolver;
197
+ /** Base directory for the registry download cache. Defaults to ~/.fhir-oas. */
198
+ cacheDir?: string;
199
+ fetchImpl?: typeof fetch;
200
+ }
201
+ /**
202
+ * Resolves the `--ig` input to an IgContext. Accepts a path to a package
203
+ * tarball (`.tgz`), a path to an unpacked package directory, or a registry
204
+ * coordinate (`name` or `name@version`) fetched from packages.fhir.org and
205
+ * cached locally. Async because registry coordinates hit the network.
206
+ */
207
+ declare function loadIg(input: string, options?: LoadIgOptions): Promise<IgContext>;
208
+ /**
209
+ * Synchronous IG loader for local inputs (a `.tgz` or an unpacked directory).
210
+ * Registry coordinates require the async {@link loadIg} because they fetch
211
+ * over the network.
212
+ */
213
+ declare function loadIgSync(input: string, options?: LoadIgOptions): IgContext;
214
+
215
+ interface MergeOptions {
216
+ /** Overwrite conflicting entries instead of failing. */
217
+ force?: boolean;
218
+ }
219
+ interface MergeConflict {
220
+ /** e.g. "components.schemas.Patient" or "paths./Patient/{id}" */
221
+ location: string;
222
+ }
223
+ declare class MergeConflictError extends Error {
224
+ readonly conflicts: MergeConflict[];
225
+ constructor(conflicts: MergeConflict[]);
226
+ }
227
+ /**
228
+ * Merges a generated OpenAPI document into existing YAML text, preserving the
229
+ * existing file's comments, anchors, and key order. Generated entries are
230
+ * added alongside existing content; an existing entry with different content
231
+ * is a conflict (all conflicts are reported; nothing is written unless every
232
+ * conflict is resolved by `force`). Identical entries are left untouched, so
233
+ * re-running the generator is idempotent.
234
+ */
235
+ declare function mergeIntoYaml(generated: OpenApiDocument, existingText: string, options?: MergeOptions): string;
236
+ interface SpecDiff {
237
+ /** Entries the file lacks (dot paths), e.g. "components.schemas.Patient". */
238
+ missing: string[];
239
+ /** Entries present in the file but differing from generation. */
240
+ changed: string[];
241
+ /** True when the file already contains exactly what generation produces. */
242
+ inSync: boolean;
243
+ }
244
+ /**
245
+ * Compares existing spec text against a generated document without writing
246
+ * anything — the CI drift guard behind `fhir-oas check`. The file is in sync
247
+ * when a merge would be a no-op: nothing to add, nothing conflicting.
248
+ */
249
+ declare function diffAgainstYaml(generated: OpenApiDocument, existingText: string): SpecDiff;
250
+ /** Serializes a generated document to YAML text. */
251
+ declare function stringifyDocument(generated: OpenApiDocument): string;
252
+
253
+ export { type Capability, type CapabilityLike, FHIR_VERSIONS, FHIR_VERSION_NUMBERS, type FhirVersion, type GenerateOptions, type IgContext, type IgContextLike, type IgProfile, type MergeConflict, MergeConflictError, type MergeOptions, type OpenApiDocument, type OpenApiVersion, type ResourceCapability, type SourceBackend, type SpecDiff, type TrimOptions, diffAgainstYaml, generateOpenApi, listResources, loadCapabilityStatement, loadIg, loadIgSync, mergeIntoYaml, parseCapabilityStatement, stringifyDocument };
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ import {
2
+ FHIR_VERSIONS,
3
+ FHIR_VERSION_NUMBERS,
4
+ MergeConflictError,
5
+ diffAgainstYaml,
6
+ generateOpenApi,
7
+ listResources,
8
+ loadCapabilityStatement,
9
+ loadIg,
10
+ loadIgSync,
11
+ mergeIntoYaml,
12
+ parseCapabilityStatement,
13
+ stringifyDocument
14
+ } from "./chunk-G3DCRADV.js";
15
+ export {
16
+ FHIR_VERSIONS,
17
+ FHIR_VERSION_NUMBERS,
18
+ MergeConflictError,
19
+ diffAgainstYaml,
20
+ generateOpenApi,
21
+ listResources,
22
+ loadCapabilityStatement,
23
+ loadIg,
24
+ loadIgSync,
25
+ mergeIntoYaml,
26
+ parseCapabilityStatement,
27
+ stringifyDocument
28
+ };
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,200 @@
1
+ # fhir-openapi-translator — Reference
2
+
3
+ Full CLI, library API, codegen recipes, and limitations. For a quick start see the [README](../README.md).
4
+
5
+ ## Contents
6
+
7
+ - [CLI](#cli)
8
+ - [Library API](#library-api)
9
+ - [Codegen recipes](#codegen-recipes)
10
+ - [Viewing generated specs](#viewing-generated-specs)
11
+ - [What this is for — and what it is not](#what-this-is-for--and-what-it-is-not)
12
+ - [Profiles: what `--profile` applies](#profiles-what---profile-applies)
13
+ - [Assumptions and known limitations](#assumptions-and-known-limitations)
14
+ - [Development](#development)
15
+
16
+ ## CLI
17
+
18
+ ```sh
19
+ # Generate a spec for Patient and Observation on FHIR R4, as YAML to stdout
20
+ fhir-oas generate Patient Observation --fhir-version r4
21
+
22
+ # Write JSON, target OpenAPI 3.1
23
+ fhir-oas generate Patient -f r5 --format json --openapi-version 3.1 -o patient.json
24
+
25
+ # Merge into an existing spec, keeping its comments and key order
26
+ fhir-oas generate Questionnaire -f r4 --merge-into api.yaml
27
+
28
+ # Embed a server URL and trim the output
29
+ fhir-oas generate Patient -f r4 --base-url https://fhir.example.org/r4 \
30
+ --exclude-narrative --max-depth 3
31
+
32
+ # List the resource types available for a version
33
+ fhir-oas list --fhir-version r4b
34
+
35
+ # CI drift guard: fail when api.yaml no longer matches generation
36
+ fhir-oas check Patient Observation -f r4 --file api.yaml
37
+
38
+ # Lenient models: replace binding enums with plain strings
39
+ fhir-oas generate Patient -f r4 --no-enums
40
+
41
+ # Include the standard operations (GET /Patient/{id}/$everything, POST /Patient/$validate, ...)
42
+ fhir-oas generate Patient -f r4 --operations
43
+
44
+ # Apply a profile from an Implementation Guide package
45
+ fhir-oas generate Patient -f r4 --ig ./hl7.fhir.us.core-5.0.1.tgz --profile us-core-patient
46
+ fhir-oas generate Patient -f r4 --ig hl7.fhir.us.core@5.0.1 --profile us-core-patient # fetched + cached
47
+
48
+ # List the profiles in an IG package
49
+ fhir-oas list --ig ./hl7.fhir.us.core-5.0.1.tgz
50
+
51
+ # Match a specific server's declared surface (resources, interactions, search params, operations)
52
+ fhir-oas generate -f r4 --capability https://server.example.org/fhir # appends /metadata
53
+ fhir-oas generate -f r4 --capability ./metadata.json # or a saved statement
54
+ ```
55
+
56
+ `fhir-oas generate --help` shows all options, including `--source` (definition backend: `schema-json` default, or `structure-def`), `--title`, and `--force` (overwrite conflicting entries when merging).
57
+
58
+ ## Library API
59
+
60
+ ```ts
61
+ import { generateOpenApi, listResources, mergeIntoYaml } from "fhir-openapi-translator";
62
+
63
+ const doc = generateOpenApi({
64
+ resources: ["Patient", "Observation"],
65
+ fhirVersion: "r4",
66
+ openApiVersion: "3.0.3", // default
67
+ baseUrl: "https://fhir.example.org/r4",
68
+ trim: { excludeNarrative: true, maxDepth: 3 },
69
+ });
70
+
71
+ listResources("r5"); // ["Account", "ActivityDefinition", ...]
72
+
73
+ // Merge into existing YAML text, preserving comments and formatting
74
+ const mergedYaml = mergeIntoYaml(doc, existingYamlText, { force: false });
75
+ ```
76
+
77
+ Profiles from an IG package (`loadIg` is async for registry coordinates; a local path can be passed to `ig` directly):
78
+
79
+ ```ts
80
+ import { generateOpenApi, loadIg } from "fhir-openapi-translator";
81
+
82
+ const ig = await loadIg("hl7.fhir.us.core@5.0.1"); // or "./us-core.tgz", or a directory
83
+ const doc = generateOpenApi({
84
+ resources: ["Patient"],
85
+ fhirVersion: "r4",
86
+ ig, // or ig: "./us-core.tgz" (loaded synchronously)
87
+ profiles: ["us-core-patient"],
88
+ });
89
+ ```
90
+
91
+ Match a server's CapabilityStatement (`loadCapabilityStatement` is async; `parseCapabilityStatement` takes an already-loaded object):
92
+
93
+ ```ts
94
+ import { generateOpenApi, loadCapabilityStatement } from "fhir-openapi-translator";
95
+
96
+ const capability = await loadCapabilityStatement("https://server.example.org/fhir");
97
+ const doc = generateOpenApi({ fhirVersion: "r4", capability }); // resources come from the statement
98
+ ```
99
+
100
+ See `GenerateOptions` in the type declarations for the full API surface.
101
+
102
+ ## Codegen recipes
103
+
104
+ Generated specs are exercised against [openapi-generator](https://github.com/OpenAPITools/openapi-generator) in CI (`typescript-fetch` and `python` targets). Notes that matter in practice:
105
+
106
+ - **typescript-fetch**: pass `--additional-properties=modelPropertyNaming=original`. FHIR represents extensions on primitive fields as sibling `_field` properties; the generator's default naming strips the underscore and produces colliding class members.
107
+ - Large resources produce large model trees (a Patient R4 spec has ~80 schemas, a full Bundle-of-anything far more). If your generator or build struggles, use `--exclude-narrative` and `--max-depth` to shrink the graph.
108
+ - `Bundle.entry.resource` (`ResourceList`) is narrowed to the resource types you requested. If your server returns other types in bundles (e.g. `_include`d resources you didn't generate), either add those resources to the generation, or treat unknown entries as opaque JSON.
109
+
110
+ ## Viewing generated specs
111
+
112
+ Swagger UI is fine for a spec covering a handful of resources, but it renders
113
+ every schema in the document eagerly. FHIR's schemas are large and mutually
114
+ recursive, so it degrades sharply as the spec grows. Measured on specs from
115
+ this tool:
116
+
117
+ | Spec | Swagger UI behaviour |
118
+ |---|---|
119
+ | 2 resources (~73 schemas) | renders fine; models expand promptly |
120
+ | 6 resources (~84 schemas) | renders, but expanding one operation blocks the page for ~90s |
121
+ | 39 resources (~188 schemas) | the **Schemas** section never finished rendering (gave up after 5 minutes) |
122
+
123
+ [Redoc](https://github.com/Redocly/redoc) renders lazily and copes with these
124
+ specs far better. Prefer it for anything beyond a few resources:
125
+
126
+ ```sh
127
+ npx @redocly/cli preview-docs fhir-r4.openapi.yaml
128
+ ```
129
+
130
+ This is a *viewer* limitation, not a defect in the generated specs — they
131
+ validate against the OpenAPI meta-schemas and feed code generators cleanly at
132
+ any size. If you do need Swagger UI on a large spec, `--exclude-narrative` and
133
+ `--max-depth` shrink the schema graph considerably.
134
+
135
+ ## What this is for — and what it is not
136
+
137
+ **Intended use**
138
+
139
+ - Generate typed FHIR models and API clients in any language — especially where no mature FHIR SDK exists (Go, Rust, Kotlin, PHP, C++, ...).
140
+ - Publish an OpenAPI contract to the consumers of your FHIR API, so they integrate against a spec rather than prose.
141
+ - Build typed clients for orchestrator-style FHIR endpoints your services call.
142
+ - Feed API gateways, contract-testing tools, mock servers, and documentation portals that speak OpenAPI.
143
+ - Commit the generated spec next to your service and regenerate on FHIR version bumps; merge mode keeps hand-written spec content intact.
144
+
145
+ **Not intended for — do not use this as**
146
+
147
+ - **A FHIR validator.** Passing schema validation does *not* make a resource FHIR-conformant: FHIRPath invariants, terminology bindings, and profile constraints (slicing, must-support, cardinality refinements) are not fully represented in OpenAPI. Validate with a real FHIR validator (HAPI, the official validator, server-side `$validate`).
148
+ - **A full profile / conformance engine.** `--profile` applies the *representable* profile constraints (see the table below), but slicing, extension slices, `pattern[x]`, FHIRPath invariants, and must-support are **not enforced** — they are surfaced as description notes and `x-fhir-constraints-omitted`, not as schema rules.
149
+ - **A replacement for a full FHIR SDK.** HAPI FHIR and Firely offer richer, spec-aware models and conformance tooling than any OpenAPI codegen can; where you need that depth, use them alongside this rather than instead of it.
150
+ - **XML payload handling.** Only the FHIR JSON representation is modeled.
151
+
152
+ ## Profiles: what `--profile` applies
153
+
154
+ Given `--ig <package> --profile <id>`, the profile snapshot is turned into a schema named after the profile (`USCorePatient`), referenced from the base `/Patient` paths:
155
+
156
+ | Profile constraint | Schema effect |
157
+ |---|---|
158
+ | `min ≥ 1` | property becomes `required` |
159
+ | `max: "0"` | property omitted |
160
+ | `max: "1"` on a base array | scalar instead of array |
161
+ | required binding, resolvable ValueSet (IG-local, then vendored core; ≤150 codes) | inline `enum` |
162
+ | `fixed[x]` | `const` (3.1) / single-value `enum` (3.0.3) |
163
+ | choice-type narrowing | only the permitted `value[x]` expansions emitted |
164
+ | `pattern[x]`, slicing, invariants, must-support | *not enforced* — noted in `description` + `x-fhir-constraints-omitted` |
165
+
166
+ The IG package is a local `.tgz` / unpacked directory, or a `name@version` coordinate fetched from `packages.fhir.org` and cached under `~/.fhir-oas/packages`. Profiles must ship a snapshot (differential-only packages error); the package FHIR version must match `--fhir-version`; only the public registry is supported (no auth).
167
+
168
+ ## Assumptions and known limitations
169
+
170
+ - Output is inherently lossy relative to the FHIR specification (see above); it trades fidelity for reach across language ecosystems.
171
+ - Enums cover *required* bindings whose ValueSet expands to a bounded code list (≤150 codes, no filters); extensible/preferred bindings and open code systems (BCP-47 languages, MIME types) stay plain strings by design.
172
+ - Primitive-extension properties (`_field`) are kept for JSON fidelity; they roughly double the property count of each model.
173
+ - Search parameters are typed as strings (except `_count`), because FHIR search values carry prefixes and modifiers (`ge2021-01-01`, `code:below=...`) that stricter types would reject. The FHIR type is preserved in `x-fhir-search-type`.
174
+ - Operations are resource-scoped only: system-level operations (`GET /$export`-style, `$convert`, ...), `POST /_search`, batch/transaction semantics, and conditional headers beyond `If-Match` are not modeled. Multi-part operation parameters collapse to a generic `Parameters` body.
175
+ - `--capability` reflects a server's *declared* surface: resource types the FHIR version doesn't define are skipped, and declared operations are emitted only when they map to a known OperationDefinition (system-level interactions like transaction/batch are not modeled). It restricts what's generated; it does not verify the server actually behaves as declared.
176
+ - The two definition backends can differ cosmetically (e.g. naming of deeply nested backbone elements, primitive regex patterns); `schema-json` is the default and the reference.
177
+
178
+ ## Development
179
+
180
+ ```sh
181
+ npm install
182
+ npm run typecheck
183
+ npm test # vitest; validates generated specs against the OpenAPI meta-schemas
184
+ npm run build # tsup → dist/
185
+ ```
186
+
187
+ Vendored FHIR definitions live in `definitions/` as gzipped JSON. To refresh them from their upstream npm packages, run:
188
+
189
+ ```sh
190
+ node scripts/update-definitions.mjs
191
+ ```
192
+
193
+ The README demo (`docs/demo.gif`) is regenerated by `scripts/make-demo.mjs`. It
194
+ drives a real generation plus Swagger UI in headless Chromium, so it needs
195
+ dev-only tooling that is deliberately kept out of `package.json`:
196
+
197
+ ```sh
198
+ npm install --no-save playwright swagger-ui-dist gifenc pngjs
199
+ npm run build && node scripts/make-demo.mjs
200
+ ```
package/docs/demo.gif ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "fhir-openapi-translator",
3
+ "version": "0.1.0",
4
+ "description": "Generate an OpenAPI (Swagger) spec for any FHIR resource (R4/R4B/R5) — for typed model & client codegen in any language. Supports US Core profiles, operations, and CapabilityStatements.",
5
+ "keywords": [
6
+ "fhir",
7
+ "fhir-to-openapi",
8
+ "openapi",
9
+ "swagger",
10
+ "hl7",
11
+ "hl7-fhir",
12
+ "codegen",
13
+ "code-generation",
14
+ "fhir-codegen",
15
+ "us-core",
16
+ "structuredefinition",
17
+ "capabilitystatement",
18
+ "healthcare",
19
+ "healthcare-interoperability",
20
+ "openapi-generator",
21
+ "fhir-r4",
22
+ "fhir-r5"
23
+ ],
24
+ "license": "MIT",
25
+ "author": "krishgok",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/krishgok/fhir-openapi-translator.git"
29
+ },
30
+ "homepage": "https://github.com/krishgok/fhir-openapi-translator#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/krishgok/fhir-openapi-translator/issues"
33
+ },
34
+ "type": "module",
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "bin": {
39
+ "fhir-oas": "dist/cli.js"
40
+ },
41
+ "main": "dist/index.js",
42
+ "types": "dist/index.d.ts",
43
+ "exports": {
44
+ ".": {
45
+ "types": "./dist/index.d.ts",
46
+ "import": "./dist/index.js"
47
+ }
48
+ },
49
+ "files": [
50
+ "dist",
51
+ "definitions",
52
+ "docs"
53
+ ],
54
+ "scripts": {
55
+ "build": "tsup",
56
+ "prepare": "npm run build",
57
+ "typecheck": "tsc --noEmit",
58
+ "test": "vitest run",
59
+ "test:watch": "vitest",
60
+ "lint": "eslint src test",
61
+ "prepublishOnly": "npm run typecheck && npm run lint && npm run build && npm run test"
62
+ },
63
+ "dependencies": {
64
+ "commander": "^12.1.0",
65
+ "yaml": "^2.6.0"
66
+ },
67
+ "devDependencies": {
68
+ "@seriousme/openapi-schema-validator": "^2.9.0",
69
+ "@types/node": "^22.9.0",
70
+ "eslint": "^9.14.0",
71
+ "openapi-types": "^12.1.3",
72
+ "tsup": "^8.3.5",
73
+ "typescript": "^5.6.3",
74
+ "typescript-eslint": "^8.13.0",
75
+ "vitest": "^2.1.4"
76
+ }
77
+ }