Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 69 additions & 62 deletions src/run/FshToFhir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,76 +29,83 @@ export async function fshToFhir(
// track errors and warnings, and determine log level from options
errorsAndWarnings.reset();
errorsAndWarnings.shouldTrack = true;
if (options.logLevel == 'silent') {
logger.transports[0].silent = true;
} else if (options.logLevel != null) {
if (!isLevel(options.logLevel)) {
return {
fhir: null,
errors: [
{
message: `Invalid logLevel: ${options.logLevel}. Valid levels include: ${levels.join(
', '
)}.`
}
],
warnings: []
};
const originalSilent = logger.transports[0].silent;
const originalLevel = logger.level;
try {
if (options.logLevel == 'silent') {
logger.transports[0].silent = true;
} else if (options.logLevel != null) {
if (!isLevel(options.logLevel)) {
return {
fhir: null,
errors: [
{
message: `Invalid logLevel: ${options.logLevel}. Valid levels include: ${levels.join(
', '
)}.`
}
],
warnings: []
};
}
logger.level = options.logLevel;
}
logger.level = options.logLevel;
}

const snapshot = options.snapshot ?? false;
const snapshot = options.snapshot ?? false;

// set up a config so that sushi can run
const config = {
canonical: options.canonical ?? 'http://example.org',
FSHOnly: true,
fhirVersion: [options.fhirVersion ?? '4.0.1'],
dependencies: options.dependencies,
version: options.version
};
// set up a config so that sushi can run
const config = {
canonical: options.canonical ?? 'http://example.org',
FSHOnly: true,
fhirVersion: [options.fhirVersion ?? '4.0.1'],
dependencies: options.dependencies,
version: options.version
};

// load dependencies
const defs = await createFHIRDefinitions();
await loadExternalDependencies(defs, config);
// load dependencies
const defs = await createFHIRDefinitions();
await loadExternalDependencies(defs, config);

// load FSH text into memory
const rawFSHes: RawFSH[] = [];
if (Array.isArray(input)) {
input.forEach((input, i) => {
rawFSHes.push(new RawFSH(input, `Input_${i}`));
});
} else {
rawFSHes.push(new RawFSH(input));
}
const tank = fillTank(rawFSHes, config);
tank.checkDuplicateNameEntities();
// load FSH text into memory
const rawFSHes: RawFSH[] = [];
if (Array.isArray(input)) {
input.forEach((input, i) => {
rawFSHes.push(new RawFSH(input, `Input_${i}`));
});
} else {
rawFSHes.push(new RawFSH(input));
}
const tank = fillTank(rawFSHes, config);
tank.checkDuplicateNameEntities();

// process FSH text into FHIR
const outPackage = exportFHIR(tank, defs);
const fhir: any[] = [];
(
[
'profiles',
'extensions',
'instances',
'valueSets',
'codeSystems',
'logicals',
'resources'
] as const
).forEach(artifactType => {
outPackage[artifactType].forEach((artifact: { toJSON: (snapshot: boolean) => any }) => {
fhir.push(artifact.toJSON(snapshot));
// process FSH text into FHIR
const outPackage = exportFHIR(tank, defs);
const fhir: any[] = [];
(
[
'profiles',
'extensions',
'instances',
'valueSets',
'codeSystems',
'logicals',
'resources'
] as const
).forEach(artifactType => {
outPackage[artifactType].forEach((artifact: { toJSON: (snapshot: boolean) => any }) => {
fhir.push(artifact.toJSON(snapshot));
});
});
});

return {
fhir,
errors: errorsAndWarnings.errors,
warnings: errorsAndWarnings.warnings
};
return {
fhir,
errors: errorsAndWarnings.errors,
warnings: errorsAndWarnings.warnings
};
} finally {
logger.transports[0].silent = originalSilent;
logger.level = originalLevel;
}
}

// *** WARNING ***
Expand Down
51 changes: 49 additions & 2 deletions test/run/FshToFhir.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ describe('#FshToFhir', () => {
});

it('should use a higher logging level when specified', async () => {
loadSpy.mockImplementationOnce(() => {
expect(logger.level).toBe('error');
expect(logger.transports[0].silent).toBeFalsy();
return Promise.resolve();
});
const results = await fshToFhir('Bad FSH', { logLevel: 'error' });
expect(results.errors).toHaveLength(1);
expect(results.errors[0].location).toEqual({
Expand All @@ -45,10 +50,15 @@ describe('#FshToFhir', () => {
expect(results.errors[0].message).toMatch(/mismatched input 'Bad'/);
expect(results.warnings).toHaveLength(0);
expect(results.fhir).toEqual([]);
expect(logger.level).toBe('error');
expect(logger.level).toBe('info');
expect(logger.transports[0].silent).toBeFalsy();
});

it('should mute the logger when "silent" is specified', async () => {
loadSpy.mockImplementationOnce(() => {
expect(logger.transports[0].silent).toBe(true);
return Promise.resolve();
});
const results = await fshToFhir('Bad FSH', { logLevel: 'silent' });
expect(results.errors).toHaveLength(1);
expect(results.errors[0].location).toEqual({
Expand All @@ -61,7 +71,7 @@ describe('#FshToFhir', () => {
expect(results.errors[0].message).toMatch(/mismatched input 'Bad'/);
expect(results.warnings).toHaveLength(0);
expect(results.fhir).toEqual([]);
expect(logger.transports[0].silent).toBe(true);
expect(logger.transports[0].silent).toBeFalsy();
});

it('should quit and return an error when an invalid logLevel is specified', async () => {
Expand All @@ -75,6 +85,43 @@ describe('#FshToFhir', () => {
expect(results.fhir).toBeNull();
});

describe('#LoggerIsolation', () => {
it('should not stay silent when a later call uses a non-silent logLevel', async () => {
await fshToFhir('', { logLevel: 'silent' });
expect(logger.transports[0].silent).toBeFalsy();

loadSpy.mockImplementationOnce(() => {
expect(logger.transports[0].silent).toBeFalsy();
expect(logger.level).toBe('error');
return Promise.resolve();
});
await fshToFhir('', { logLevel: 'error' });
expect(logger.transports[0].silent).toBeFalsy();
expect(logger.level).toBe('info');
});

it('should not keep a previous logLevel when a later call omits logLevel', async () => {
await fshToFhir('', { logLevel: 'error' });

loadSpy.mockImplementationOnce(() => {
expect(logger.level).toBe('info');
expect(logger.transports[0].silent).toBeFalsy();
return Promise.resolve();
});
await fshToFhir('');
expect(logger.level).toBe('info');
});

it('should restore the logger when processing fails', async () => {
loadSpy.mockImplementationOnce(() => {
throw new Error('dependency load failed');
});
await expect(fshToFhir('', { logLevel: 'silent' })).rejects.toThrow('dependency load failed');
expect(logger.transports[0].silent).toBeFalsy();
expect(logger.level).toBe('info');
});
});

it('should replace configuration options when specified', async () => {
await expect(
fshToFhir('', {
Expand Down
Loading