Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fhir 4 typescript #964

Draft
wants to merge 66 commits into
base: main
Choose a base branch
from
Draft

Fhir 4 typescript #964

wants to merge 66 commits into from

Conversation

josephjclark
Copy link
Collaborator

@josephjclark josephjclark commented Jan 30, 2025

FHIR r4 adaptor with auto-generated typescript.

Replaces #909

This is a fully typescript implementation, so we get really good type definitions out of it, which gives us great code-assist support.

I am not using the npm fhir package for typings. It just doesn't work very well for us, and introduces a problem bundling for Monaco. Also it exposes _ variants of each property, for extensions. Which really pollutes the code assist.

Code assist is now provided in test files (which makes writing unit tests easier AND more lightning-like) as well as in Lightning. I've tested it locally, works great.

Major changes:

  • Update jsdocs2md to support typescript docs. I think this was necessary but doesn't introduce any changes to existing adaptors
  • This would be our first typescript-first adaptor. Cool.
  • I have condensed the generated code to be more terse and permissive. Whatever the user passes in is spread into the result. So you can do whatever you like
  • The builder signature now overloaded. You can do b.patient('Patient', { ...}) or b.patient({ ... }). Profile names aren't actually needed or useful here, but I want to keep API consistency with the IG adaptors. It works well.

Still do to before release:

  • Add basic operations with fhir verbs - http, read, create, update, bundle
  • I think I'll absorb the datatypes stuff into builders, so you can do b.concept, b.identifier.
  • Properly extract meta and text properties from the generator, and let uses provide extension hooks for this in the mappings file DONE
  • Manually write out a few tests for key types. This helps validates improvements
  • Add a good docs overview and some examples to showcase best practice
  • Fix docs for composite keys like deceased[x].
  • Should we be a lot more restrictive in the builders we support? We include almost everything but maybe we should only include the medical stuff

Also note that this totally breaks the implementation guide generator. I'm tracking that in #955

Spin out issues to do later:

  • Parse valuesets to allow auto-complete for basic types (like human name enums)
  • Use valuesets to map simple string values to system/coded concepts
  • Better support for extensions
  • Allow job code to set mapping values. So that I can pass any arbitrary object to, eg, patient.identifier, and the mapping function will handle the mapping. Essentially we allow custom support for value mapping. This should make mapping to fhir MUCH easier

AI Disclaimer

I used a little Claude wisdom to help work out how to handle some of the typings.

Core fhir definitions seem use a different bundle structure to the regular IG definitions. Basically the folder structure is a bit different and the resources are all captured in a single bundle.

This commit adds a solution which seems to work in fhir 4 at least
Put each profile in its own file, and just the entrypoints in  builders.js
We need these for the docsite anyway - but they're not a good solution for driving ts
A good way to sketch out the value of the builder APIs. Not sure we're coming out ahead yet
Accidentally used an overly restrictive mapping
this includes referneces to @types/fhir with _ props removed

works in unit tests now, hurrah!
plus some tool tidyups
now we get instant type tracking in the builders
@josephjclark
Copy link
Collaborator Author

josephjclark commented Feb 25, 2025

I've just been doing my final flight checks, getting ready for release and running some extra tests.

And I've hit the weirdest issue. It's taken a while to whittle it down to barebones.

If I make index.d.ts say this:

type Identifier = {
  foo: 'string';
  bar: 'string';
};
declare const identifier: (id: Identifier) => string;

export { identifier };

Everything is fine, I get code assist in monaco for the identifier.

if I change the signature to this:

declare const identifier: (id: string | Identifier) => string;

I get no type assist at all.

It's like adding the string union blows it up. A union like 'foo' | 'bar' works great.

Works just fine in the monaco playground for 0.43 (the version we're running)

I've disabled the magic code completion stuff. Still breaks.

Edit: it works if I disable nolib: true. So it's a language support thing. Something about the string type.

Edit #2: same in Monaco playground. With nolib it's totally bailing on this type support.

@josephjclark
Copy link
Collaborator Author

I think I'm gonna have to cut out these string | Identifier shorthand types and call this a Lightning bug. Very frustrating. We have a parallel work stream in this area so maybe it can get looked at there.

@josephjclark
Copy link
Collaborator Author

Ok, incredibly, what we have to do is add this in the es5 language definition in Monaco:

interface Array<T> {
    copyWithin(target: number, start: number, end?: number): this;
    [n: number]: T;
}

I don't understand it at all - but the type tracking totally breaks down when typings for Array.copyWithin() aren't present.

Raising a PR against Lightning now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Icebox
Development

Successfully merging this pull request may close these issues.

1 participant