Skip to content

Commit

Permalink
Log a warning when conformance or terminology instances will default …
Browse files Browse the repository at this point in the history
…to example usage
  • Loading branch information
jafeltra committed Aug 24, 2023
1 parent 0a37371 commit 47306ce
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
22 changes: 18 additions & 4 deletions src/import/FSHImporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
OnlyRuleType,
PathRule
} from '../fshtypes/rules';
import { splitOnPathPeriods } from '../fhirtypes/common';
import { CONFORMANCE_AND_TERMINOLOGY_RESOURCES, splitOnPathPeriods } from '../fhirtypes/common';
import { ParserRuleContext, InputStream, CommonTokenStream, TerminalNode } from 'antlr4';
import { logger, switchToSecretLogger, LoggerData, restoreMainLogger } from '../utils/FSHLogger';
import {
Expand Down Expand Up @@ -430,17 +430,18 @@ export class FSHImporter extends FSHVisitor {
}

visitInstance(ctx: pc.InstanceContext) {
const location = this.extractStartStop(ctx);
const instance = new Instance(ctx.name().getText())
.withLocation(this.extractStartStop(ctx))
.withLocation(location)
.withFile(this.currentFile);
if (this.docs.some(doc => doc.instances.has(instance.name))) {
logger.error(`Skipping Instance: an Instance named ${instance.name} already exists.`, {
file: this.currentFile,
location: this.extractStartStop(ctx)
location
});
} else {
try {
this.parseInstance(instance, ctx.instanceMetadata(), ctx.instanceRule());
this.parseInstance(instance, location, ctx.instanceMetadata(), ctx.instanceRule());
this.currentDoc.instances.set(instance.name, instance);
} catch (e) {
logger.error(e.message, instance.sourceInfo);
Expand All @@ -450,6 +451,7 @@ export class FSHImporter extends FSHVisitor {

private parseInstance(
instance: Instance,
location: TextLocation,
metaCtx: pc.InstanceMetadataContext[] = [],
ruleCtx: pc.InstanceRuleContext[] = []
): void {
Expand Down Expand Up @@ -483,6 +485,18 @@ export class FSHImporter extends FSHVisitor {
if (!instance.instanceOf) {
throw new RequiredMetadataError('InstanceOf', 'Instance', instance.name);
}
if (
CONFORMANCE_AND_TERMINOLOGY_RESOURCES.has(instance.instanceOf) &&
!metaCtx.some(ctx => ctx.usage())
) {
logger.warn(
`No usage was specified on ${instance.name} so the default #example is used, but ${instance.instanceOf} Instances likely are definitions. Specify a usage to resolve this warning.`,
{
file: this.currentFile,
location
}
);
}
ruleCtx.forEach(instanceRule => {
const rule = this.visitInstanceRule(instanceRule);
if (rule) {
Expand Down
25 changes: 25 additions & 0 deletions test/import/FSHImporter.Instance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { importSingleText } from '../testhelpers/importSingleText';
import { importText, RawFSH } from '../../src/import';

describe('FSHImporter', () => {
beforeEach(() => {
loggerSpy.reset();
});

describe('Instance', () => {
describe('#instanceOf', () => {
it('should parse the simplest possible instance', () => {
Expand Down Expand Up @@ -156,6 +160,27 @@ describe('FSHImporter', () => {
);
expect(loggerSpy.getLastMessage('warn')).toMatch(/File: Bad\.fsh.*Line: 4\D*/s);
});

it('should log a warning if a conformance or terminology resource does not have a usage (and therefore will default to example)', () => {
// No usage specified for a CapabilityStatement instance
const input = `
Instance: MyCapabilityStatementDefinition
InstanceOf: CapabilityStatement
`;

const result = importSingleText(input, 'CS.fsh');
expect(result.instances.size).toBe(1);
const instance = result.instances.get('MyCapabilityStatementDefinition');
expect(instance.name).toBe('MyCapabilityStatementDefinition');
expect(instance.instanceOf).toBe('CapabilityStatement');
expect(instance.usage).toBe('Example'); // default is still used but warning is logged
expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
expect(loggerSpy.getAllMessages('warn')).toHaveLength(1);
expect(loggerSpy.getLastMessage('warn')).toMatch(
/No usage was specified on MyCapabilityStatementDefinition so the default #example is used, but CapabilityStatement Instances likely are definitions/s
);
expect(loggerSpy.getLastMessage('warn')).toMatch(/File: CS\.fsh.*Line: 2 - 3\D*/s);
});
});

describe('#mixins', () => {
Expand Down

0 comments on commit 47306ce

Please sign in to comment.