Merge pull request #318 from ahdis/oe_structuremaps

structure maps: line comments and fhir path expression
This commit is contained in:
Grahame Grieve 2020-08-26 12:51:10 +10:00 committed by GitHub
commit f52297ae26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 32 deletions

View File

@ -284,7 +284,10 @@ public class StructureMapUtilities {
b.append("\" = \"");
b.append(Utilities.escapeJson(map.getName()));
b.append("\"\r\n\r\n");
if (map.getDescription()!=null) {
renderMultilineDoco(b, map.getDescription(), 0);
b.append("\r\n");
}
renderConceptMaps(b, map);
renderUses(b, map);
renderImports(b, map);
@ -392,8 +395,8 @@ public class StructureMapUtilities {
}
b.append("as ");
b.append(s.getMode().toCode());
b.append("\r\n");
renderDoco(b, s.getDocumentation());
b.append("\r\n");
}
if (map.hasStructure())
b.append("\r\n");
@ -416,6 +419,9 @@ public class StructureMapUtilities {
}
private static void renderGroup(StringBuilder b, StructureMapGroupComponent g) {
if (g.hasDocumentation()) {
renderMultilineDoco(b, g.getDocumentation(), 0);
}
b.append("group ");
b.append(g.getName());
b.append("(");
@ -464,6 +470,9 @@ public class StructureMapUtilities {
}
private static void renderRule(StringBuilder b, StructureMapGroupRuleComponent r, int indent) {
if (r.getDocumentation()!=null) {
renderMultilineDoco(b, r.getDocumentation(),indent);
}
for (int i = 0; i < indent; i++)
b.append(' ');
boolean canBeAbbreviated = checkisSimple(r);
@ -499,7 +508,6 @@ public class StructureMapUtilities {
}
if (r.hasRule()) {
b.append(" then {\r\n");
renderDoco(b, r.getDocumentation());
for (StructureMapGroupRuleComponent ir : r.getRule()) {
renderRule(b, ir, indent+2);
}
@ -539,8 +547,7 @@ public class StructureMapUtilities {
}
}
b.append(";");
renderDoco(b, r.getDocumentation());
b.append("\r\n");
b.append("\r\n");
}
private static boolean matchesName(String n, List<StructureMapGroupRuleSourceComponent> source) {
@ -653,13 +660,13 @@ public class StructureMapUtilities {
renderTransformParam(b, rt.getParameter().get(0));
} else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 1) {
b.append("(");
b.append("\""+((StringType) rt.getParameter().get(0).getValue()).asStringValue()+"\"");
b.append(((StringType) rt.getParameter().get(0).getValue()).asStringValue());
b.append(")");
} else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 2) {
b.append(rt.getTransform().toCode());
b.append("(");
b.append(((IdType) rt.getParameter().get(0).getValue()).asStringValue());
b.append("\""+((StringType) rt.getParameter().get(1).getValue()).asStringValue()+"\"");
b.append(((StringType) rt.getParameter().get(1).getValue()).asStringValue());
b.append(")");
} else {
b.append(rt.getTransform().toCode());
@ -718,9 +725,24 @@ public class StructureMapUtilities {
private static void renderDoco(StringBuilder b, String doco) {
if (Utilities.noString(doco))
return;
b.append(" // ");
if (b!=null && b.length()>1 && b.charAt(b.length()-1)!='\n' && b.charAt(b.length()-1)!=' ') {
b.append(" ");
}
b.append("// ");
b.append(doco.replace("\r\n", " ").replace("\r", " ").replace("\n", " "));
}
private static void renderMultilineDoco(StringBuilder b, String doco, int indent) {
if (Utilities.noString(doco))
return;
String[] lines = doco.split("\\r?\\n");
for(String line: lines) {
for (int i = 0; i < indent; i++)
b.append(' ');
renderDoco(b, line);
b.append("\r\n");
}
}
public StructureMap parse(String text, String srcName) throws FHIRException {
FHIRLexer lexer = new FHIRLexer(text, srcName);
@ -732,8 +754,9 @@ public class StructureMapUtilities {
result.setUrl(lexer.readConstant("url"));
lexer.token("=");
result.setName(lexer.readConstant("name"));
lexer.skipComments();
if (lexer.hasComment()) {
result.setDescription(getMultiLineComments(lexer));
}
while (lexer.hasToken("conceptmap"))
parseConceptMap(result, lexer);
@ -801,12 +824,24 @@ public class StructureMapUtilities {
tgt.setCode(lexer.take());
if (tgt.getCode().startsWith("\""))
tgt.setCode(lexer.processConstant(tgt.getCode()));
if (lexer.hasComment())
tgt.setComment(lexer.take().substring(2).trim());
if (lexer.hasComment())
tgt.setComment(lexer.take().substring(2).trim());
}
lexer.token("}");
}
private String getMultiLineComments(FHIRLexer lexer) {
String comment = null;
while (lexer.hasComment()) {
String newComment = lexer.take().substring(2).trim();
if (comment == null) {
comment = newComment;
} else {
comment += "\r\n"+newComment;
}
}
return comment;
}
private ConceptMapGroupComponent getGroup(ConceptMap map, String srcs, String tgts) {
for (ConceptMapGroupComponent grp : map.getGroup()) {
@ -850,6 +885,7 @@ public class StructureMapUtilities {
private void parseUses(StructureMap result, FHIRLexer lexer) throws FHIRException {
lexer.token("uses");
int currentLine = lexer.getCurrentLocation().getLine();
StructureMapStructureComponent st = result.addStructure();
st.setUrl(lexer.readConstant("url"));
if (lexer.hasToken("alias")) {
@ -859,25 +895,34 @@ public class StructureMapUtilities {
lexer.token("as");
st.setMode(StructureMapModelMode.fromCode(lexer.take()));
lexer.skipToken(";");
if (lexer.hasComment()) {
if (lexer.hasComment() && currentLine == lexer.getCurrentLocation().getLine()) {
st.setDocumentation(lexer.take().substring(2).trim());
}
lexer.skipComments();
}
private void parseImports(StructureMap result, FHIRLexer lexer) throws FHIRException {
lexer.token("imports");
int currentLine = lexer.getCurrentLocation().getLine();
result.addImport(lexer.readConstant("url"));
lexer.skipToken(";");
if (lexer.hasComment()) {
if (lexer.hasComment() && currentLine == lexer.getCurrentLocation().getLine()) {
lexer.next();
}
lexer.skipComments();
}
private void parseGroup(StructureMap result, FHIRLexer lexer) throws FHIRException {
String comment = null;
if (lexer.hasComment()) {
comment = getMultiLineComments(lexer);
if (lexer.done()) {
return ;
}
}
lexer.token("group");
StructureMapGroupComponent group = result.addGroup();
if (comment != null) {
group.setDocumentation(comment);
}
boolean newFmt = false;
if (lexer.hasToken("for")) {
lexer.token("for");
@ -923,7 +968,6 @@ public class StructureMapUtilities {
}
lexer.token("{");
}
lexer.skipComments();
if (newFmt) {
while (!lexer.hasToken("}")) {
if (lexer.done())
@ -931,6 +975,7 @@ public class StructureMapUtilities {
parseRule(result, group.getRule(), lexer, true);
}
} else {
lexer.skipComments();
while (lexer.hasToken("input"))
parseInput(group, lexer, false);
while (!lexer.hasToken("endgroup")) {
@ -942,7 +987,6 @@ public class StructureMapUtilities {
lexer.next();
if (newFmt && lexer.hasToken(";"))
lexer.next();
lexer.skipComments();
}
private void parseInput(StructureMapGroupComponent group, FHIRLexer lexer, boolean newFmt) throws FHIRException {
@ -969,12 +1013,19 @@ public class StructureMapUtilities {
private void parseRule(StructureMap map, List<StructureMapGroupRuleComponent> list, FHIRLexer lexer, boolean newFmt) throws FHIRException {
StructureMapGroupRuleComponent rule = new StructureMapGroupRuleComponent();
list.add(rule);
if (!newFmt) {
rule.setName(lexer.takeDottedToken());
lexer.token(":");
lexer.token("for");
} else {
if (lexer.hasComment()) {
rule.setDocumentation(this.getMultiLineComments(lexer));
if (lexer.hasToken("}")) {
return ; // catched a comment at the end
}
}
}
list.add(rule);
boolean done = false;
while (!done) {
parseSource(rule, lexer);
@ -996,10 +1047,6 @@ public class StructureMapUtilities {
lexer.token("then");
if (lexer.hasToken("{")) {
lexer.token("{");
if (lexer.hasComment()) {
rule.setDocumentation(lexer.take().substring(2).trim());
}
lexer.skipComments();
while (!lexer.hasToken("}")) {
if (lexer.done())
throw lexer.error("premature termination expecting '}' in nested group");
@ -1016,7 +1063,7 @@ public class StructureMapUtilities {
}
}
} else if (lexer.hasComment()) {
rule.setDocumentation(lexer.take().substring(2).trim());
rule.setDocumentation(getMultiLineComments(lexer));
}
if (isSimpleSyntax(rule)) {
rule.getSourceFirstRep().setVariable(AUTO_VAR_NAME);
@ -1041,7 +1088,6 @@ public class StructureMapUtilities {
}
lexer.token(";");
}
lexer.skipComments();
}
private boolean isSimpleSyntax(StructureMapGroupRuleComponent rule) {

View File

@ -10,23 +10,23 @@ import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.StructureMap;
import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleTargetComponent;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.StructureMapUtilities;
import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@Disabled // org.hl7.fhir.exceptions.FHIRException: Unable to resolve package id hl7.fhir.core#4.0.0
public class StructureMapUtilitiesTest implements ITransformerServices {
static private SimpleWorkerContext context;
// @BeforeAll
@BeforeAll
static public void setUp() throws Exception {
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.core", "4.0.0"));
context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1"));
}
@Test
@ -38,7 +38,43 @@ public class StructureMapUtilitiesTest implements ITransformerServices {
// StructureMap/ActivityDefinition3to4: StructureMap.group[3].rule[2].name error id value '"expression"' is not valid
assertEquals("expression", structureMap.getGroup().get(2).getRule().get(1).getName());
}
private void assertSerializeDeserialize(StructureMap structureMap) {
assertEquals("syntax", structureMap.getName());
assertEquals("Title of this map\r\nAuthor", structureMap.getDescription());
assertEquals("http://github.com/FHIR/fhir-test-cases/r5/fml/syntax", structureMap.getUrl());
assertEquals("Patient", structureMap.getStructure().get(0).getAlias());
assertEquals("http://hl7.org/fhir/StructureDefinition/Patient", structureMap.getStructure().get(0).getUrl());
assertEquals("Source Documentation", structureMap.getStructure().get(0).getDocumentation());
assertEquals("http://hl7.org/fhir/StructureDefinition/Patient", structureMap.getStructure().get(0).getUrl());
assertEquals("http://hl7.org/fhir/StructureDefinition/Basic", structureMap.getStructure().get(1).getUrl());
assertEquals("Target Documentation", structureMap.getStructure().get(1).getDocumentation());
assertEquals("Groups\r\nrule for patient group", structureMap.getGroup().get(0).getDocumentation());
assertEquals("Comment to rule", structureMap.getGroup().get(0).getRule().get(0).getDocumentation());
assertEquals("Copy identifier short syntax", structureMap.getGroup().get(0).getRule().get(1).getDocumentation());
StructureMapGroupRuleTargetComponent target = structureMap.getGroup().get(0).getRule().get(2).getTarget().get(1);
assertEquals("'urn:uuid:' + r.lower()", target.getParameter().get(0).toString());
}
@Test
public void testSyntax() throws IOException, FHIRException {
StructureMapUtilities scu = new StructureMapUtilities(context, this);
String fileMap = TestingUtilities.loadTestResource("r5", "fml", "syntax.map");
System.out.println(fileMap);
StructureMap structureMap = scu.parse(fileMap, "Syntax");
assertSerializeDeserialize(structureMap);
String renderedMap = StructureMapUtilities.render(structureMap);
StructureMap map = scu.parse(renderedMap, "Syntax");
System.out.println(map);
assertSerializeDeserialize(map);
}
@Override
public void log(String message) {
}

View File

@ -17,7 +17,7 @@
<properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.33</validator_test_case_version>
<validator_test_case_version>1.1.34-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.6.2</junit_jupiter_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version>
<jacoco_version>0.8.5</jacoco_version>