Skip to content

Commit

Permalink
Load the same automatic dependencies as SUSHI (#228)
Browse files Browse the repository at this point in the history
* Load the same automatic dependencies as SUSHI

Use SUSHI's function for loading automatic dependencies. There is a
minor discrepancy in the expected type, but the FHIR definitions are
only passed in so they can be passed to fhir-package-loader's
mergeDependency function. So, the ts-ignore here should be safe. Add a
note indicating the reason for the ts-ignore and the conditions under
which it can be removed.

* Refactor dependency loading operations

All dependency loading is now handled by loadExternalDependencies. This
function is used in both command-line and API modes. This function
determines the core FHIR package, loads automatic dependencies (as
defined by SUSHI), and loads configured dependencies.

* Check for core package before adding it

* Further update to FPL dependency
  • Loading branch information
mint-thompson committed Jul 25, 2023
1 parent 67472b7 commit 5c8bec8
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 85 deletions.
133 changes: 126 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"diff": "^5.0.0",
"diff2html": "^3.1.18",
"fhir": "^4.10.0",
"fhir-package-loader": "^0.3.0",
"fhir-package-loader": "^0.5.0",
"flat": "^5.0.2",
"fs-extra": "^9.0.1",
"fsh-sushi": "^3.1.0",
Expand Down
17 changes: 4 additions & 13 deletions src/api/FhirToFsh.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { fhirtypes, fshtypes, utils } from 'fsh-sushi';
import { fshtypes, utils } from 'fsh-sushi';
import {
determineCorePackageId,
FHIRDefinitions,
getResources,
isProcessableContent,
loadExternalDependencies,
MasterFisher,
logger,
errorsAndWarnings,
ErrorsAndWarnings
ErrorsAndWarnings,
loadExternalDependencies
} from '../utils';
import { FHIRProcessor, LakeOfFHIR, WildFHIR } from '../processor';
import { FSHExporter } from '../export';
Expand Down Expand Up @@ -81,15 +80,7 @@ export async function fhirToFsh(
);

// Load dependencies, including those inferred from an IG file, and those given as input
const dependencies =
configuration.config.dependencies?.map(
(dep: fhirtypes.ImplementationGuideDependsOn) => `${dep.packageId}@${dep.version}`
) ?? [];
const fhirPackageId = determineCorePackageId(configuration.config.fhirVersion[0]);
if (!dependencies.includes(`${fhirPackageId}@${configuration.config.fhirVersion[0]}`)) {
dependencies.push(`${fhirPackageId}@${configuration.config.fhirVersion[0]}`);
}
await Promise.all(loadExternalDependencies(defs, dependencies));
await loadExternalDependencies(defs, configuration);

// Process the FHIR to rules, and then export to FSH
const pkg = await getResources(processor, configuration, processingOptions);
Expand Down
17 changes: 4 additions & 13 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@ import fs from 'fs-extra';
import program from 'commander';
import chalk from 'chalk';
import { pad, padStart, padEnd } from 'lodash';
import { fhirtypes, utils } from 'fsh-sushi';
import { utils } from 'fsh-sushi';
import {
determineCorePackageId,
ensureOutputDir,
FHIRDefinitions,
getInputDir,
getAliasFile,
getFhirProcessor,
getResources,
loadExternalDependencies,
writeFSH,
logger,
stats,
fshingTrip,
getRandomPun,
ProcessingOptions
ProcessingOptions,
loadExternalDependencies
} from './utils';
import { Package, AliasProcessor } from './processor';
import { ExportableAlias } from './exportable';
Expand Down Expand Up @@ -202,15 +201,7 @@ async function app() {
const config = processor.processConfig(dependencies, specifiedFHIRVersion);

// Load dependencies from config for GoFSH processing
const allDependencies =
config.config.dependencies?.map(
(dep: fhirtypes.ImplementationGuideDependsOn) => `${dep.packageId}@${dep.version}`
) ?? [];
const fhirPackageId = determineCorePackageId(config.config.fhirVersion[0]);
allDependencies.push(`${fhirPackageId}@${config.config.fhirVersion[0]}`);
const dependencyDefs = loadExternalDependencies(defs, allDependencies);

await Promise.all(dependencyDefs);
await loadExternalDependencies(defs, config);

let pkg: Package;
try {
Expand Down
24 changes: 23 additions & 1 deletion src/utils/Processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ini from 'ini';
import readlineSync from 'readline-sync';
import { mergeDependency } from 'fhir-package-loader';
import { logger, logMessage } from './GoFSHLogger';
import { fhirtypes, utils } from 'fsh-sushi';
import {
Package,
FHIRProcessor,
Expand Down Expand Up @@ -112,7 +113,28 @@ export function writeFSH(resources: Package, outDir: string, style: string): voi
}
}

export function loadExternalDependencies(
export async function loadExternalDependencies(
defs: FHIRDefinitions,
config: ExportableConfiguration
) {
const allDependencies =
config.config.dependencies?.map(
(dep: fhirtypes.ImplementationGuideDependsOn) => `${dep.packageId}@${dep.version}`
) ?? [];
const fhirPackageId = determineCorePackageId(config.config.fhirVersion[0]);
if (!allDependencies.includes(`${fhirPackageId}@${config.config.fhirVersion[0]}`)) {
allDependencies.push(`${fhirPackageId}@${config.config.fhirVersion[0]}`);
}
await utils.loadAutomaticDependencies(
config.config.fhirVersion[0],
config.config.dependencies ?? [],
// @ts-ignore TODO: this can be removed once SUSHI changes the type signature for this function to use FPL's FHIRDefinitions type
defs
);
await Promise.all(loadConfiguredDependencies(defs, allDependencies));
}

export function loadConfiguredDependencies(
defs: FHIRDefinitions,
dependencies: string[] = []
): Promise<FHIRDefinitions | void>[] {
Expand Down
64 changes: 21 additions & 43 deletions test/api/FhirToFsh.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs-extra';
import path from 'path';
import * as processing from '../../src/utils/Processing';
import { fshtypes } from 'fsh-sushi';
import { logger } from '../../src/utils';
import { FHIRDefinitions, logger } from '../../src/utils';
import { fhirToFsh, ResourceMap } from '../../src/api';
import { loggerSpy } from '../helpers/loggerSpy';
import { EOL } from 'os';
Expand Down Expand Up @@ -40,7 +40,7 @@ describe('fhirToFsh', () => {
loadSpy = jest.spyOn(processing, 'loadExternalDependencies').mockImplementation(defs => {
defs.add(sd);
defs.add(patient);
return [undefined];
return Promise.resolve();
});
defaultConfig = {
FSHOnly: true,
Expand Down Expand Up @@ -111,50 +111,28 @@ describe('fhirToFsh', () => {
expect(results.configuration).toEqual(defaultConfig);
});

it('should load dependencies from user input', async () => {
// Should be able to accept both # and @ style for dependencies
const results = await fhirToFsh([], {
it('should try to load external dependencies', async () => {
await fhirToFsh([], {
dependencies: ['hl7.fhir.us.core#3.1.0', 'hl7.fhir.us.mcode@1.0.0']
});
expect(results.errors).toHaveLength(0);
expect(results.warnings).toHaveLength(1);
expect(results.warnings[0].message).toMatch('Could not determine FHIR version. Using 4.0.1.');
expect(results.fsh).toEqual('');
expect(results.configuration).toEqual({
...defaultConfig,
dependencies: [
{ packageId: 'hl7.fhir.us.core', version: '3.1.0' },
{ packageId: 'hl7.fhir.us.mcode', version: '1.0.0' }
]
});

expect(loadSpy.mock.calls).toHaveLength(1);
expect(loadSpy.mock.calls[0][1]).toEqual([
'hl7.fhir.us.core@3.1.0',
'hl7.fhir.us.mcode@1.0.0',
'hl7.fhir.r4.core@4.0.1'
]);
});

it('should load FHIR R4B when specified in config fhirVersion', async () => {
// Loads R4B from fhirVersion
const results = await fhirToFsh([
JSON.stringify({
resourceType: 'StructureDefinition',
name: 'Foo',
baseDefinition: 'http://hl7.org/fhir/StructureDefinition/Patient',
derivation: 'constraint',
fhirVersion: '4.3.0' // FHIR R4B
expect(loadSpy).toHaveBeenCalledTimes(1);
expect(loadSpy).toHaveBeenCalledWith(
expect.any(FHIRDefinitions),
expect.objectContaining({
config: expect.objectContaining({
dependencies: [
{
packageId: 'hl7.fhir.us.core',
version: '3.1.0'
},
{
packageId: 'hl7.fhir.us.mcode',
version: '1.0.0'
}
]
})
})
]);
expect(results.errors).toHaveLength(0);
expect(results.warnings).toHaveLength(0);
expect(results.configuration).toEqual({
...defaultConfig,
fhirVersion: ['4.3.0']
});
expect(loadSpy.mock.calls).toHaveLength(1);
expect(loadSpy.mock.calls[0][1]).toEqual(['hl7.fhir.r4b.core@4.3.0']);
);
});

it('should parse a string input into JSON', async () => {
Expand Down
Loading

0 comments on commit 5c8bec8

Please sign in to comment.